Kernel Interface
****************

Tasks - The execution environment
=================================

A task is an execution environment and is the basic unit of resource allocation. A task includes a paged virtual address space and protected access to system resources.

The size of the virtual address space is architecture dependent.  The Intel 80386 port of rtmk provides a 3 GB address space to the user. The kernel uses the first 1 GB of the address space, this memory is not visible to the user application.

The running task
----------------

A thread can always get the name of the send right of the task that it is currently executing in, by simply calling task_self.

 -- Task function: rtmk_port task_self (void)
     Return send rights to the task that the current executing thread is running in.  References to the task is not increased by this function, so there is no need to deallocate after usage.

Creating tasks
--------------

When creating a new task the user application can choose to fork of the parent tasks address space or create a new, empty, address space of the child task.  A newly created task is NOT suspended.

 -- Task function: kern_return_t task_create (rtmk_port_t TASK, bool FORK_P, rtmk_port_t *CHILD_TASKP)
     Creates a new task, where TASK will act as the parent task. If FORK_P is true, the address space of TASK will be forked, taking region inheritance flags in account. Send right to the new task is returned in CHILD_TASKP.  The kernel always hold receive right for a task.

 -- Task function: kern_return_t task_terminate (rtmk_port_t TASK)
     Try to terminate TASK.  When this function returns, all execution of threads in TASK have been stopped and the task have been terminated. If TASK is the current running task (i.e. we are terminating our self), this function will never return.

 -- Task function: kern_return_t task_suspend (rtmk_port_t TASK)
     Suspend execution of all threads that belong to TASK, until they are resumed.

 -- Task function: kern_return_t task_resume (rtmk_port_t TASK)
     Resume execution of all threads (except those who is individually suspended) that belong to TASK.

Task information
----------------

An application with a send right to a task can always retrieve information about that task.  thread_info returns a structure containing basic information about the task and the number of resources it is holding.

 -- Task function: kern_return_t task_threads (rtmk_port_t TASK, rtmk_port_t *THREADSP, int *COUNTP)
     This function returns an array, THREADSP, with *COUNTP entries containing send rights to all threads in TASK.  The array is out-of-line memory, so it has to be deallocated using vm_deallocate after it has been used.

 -- Task function: kern_return_t task_info (rtmk_port_t TASK, struct task_info *INFOP, int *COUNTP)
     Retrieve information about TASK and store it in *INFOP.  On call, *COUNTP must hold the value of TASK_INFO_COUNT.

 -- Task function: kern_return_t task_names (rtmk_port_t TASK, rtmk_port_name_t *RIGHTSP, int *RIGHTS_COUNTP, rtmk_port_type_t *TYPES, int *TYPES_COUNTP)
     Retrieve two arrays that hold information about names and types of all rights that TASK holds.  Arrays must be deallocated after they have been used.

Task's special ports
--------------------

Each task controls a set of special ports that are used for several purposes. Each slot in the port set contains a send right to a port that can be retrieved by a someone that holds send rights to the task.  Available slots:

TASK_SPECIAL_PORT_KERNEL
     Represents task to the outside world.  This is the port that is returned by task_self.

TASK_SPECIAL_PORT_BOOTSTRAP
     Slot can be used to identify bootstrap port that is assigned to the particular task.  The kernel does not use the bootstrap port internally, but applications can use it when forking of children.

TASK_SPECIAL_PORT_EXCEPTION
     Exception messages for task are sent to this port. See Exceptions.

There are some slots reserved for the future, and some that are free to be used by applications.

 -- Task function: kern_return_t task_special_port_set (rtmk_port_t TASK, int SLOT, rtmk_port_t PORT)
     Set control port in TASK to PORT at SLOT in control port array. (??? write something else here)

 -- Task function: kern_return_t task_special_port_get (rtmk_port_t TASK, int SLOT, rtmk_port_t *PORTP)
     Get send rights to port SLOT in TASK's control port set. Right is returned in PORTP.

Threads - the basic execution unit.
===================================

A thread is the basic unit of execution.  It consists of all processor state (e.g., hardware registers) necessary for independent execution, and scheduling information.

At any given time a thread executes in the virtual memory and port rights context of ONE single task.  But threads can migrate to other tasks, using full migrated RPC.

The conventional notion of a process is, in rtmk, represented by a task with a single thread of control.

The executing thread
--------------------

A thread can always get the name of the send right of itself, the thread that it is currently executing, by simply calling thread_self.

 -- Thread function: rtmk_port_t thread_self (void)
     Return send rights to the current executing thread.

Controling threads
------------------

When a thread is created, it is assigned to a task.  This is the task that the thread will begin to execute in, it's so called home task.

 -- Thread function: kern_return_t thread_create (rtmk_port_t TASK, rtmk_port_t *THREADP)
     Create thread that will execute in TASK.  New thread is suspended.

 -- Thread function: kern_return_t thread_terminate (rtmk_port_t THREAD)
     Terminate THREAD.

 -- Thread function: kern_return_t thread_suspend (rtmk_port_t THREAD)
     Suspend execution of THREAD.

 -- Thread function: kern_return_t thread_resume (rtmk_port_t THREAD)
     Resume execution of THREAD if suspend count drops to zero.

Reply ports
-----------

To perform a RPC the thread needs a reply port to receive the reply on. To allocate this port using port_allocate would cause to much overhead. The thread_reply_port system call return right name to a newly allocated port, that can be used for receiving replies.

 -- Thread function: rtmk_port_t thread_reply_port (void)
     Allocate a port that can be used a receive port of replies.

Special ports
-------------

Each thread, just like tasks, controls a set of special ports. Each slot in the port set contains a send right to a port that can be retrieved by a someone that holds send rights to the task.  Available slots:

THREAD_SPECIAL_PORT_KERNEL
     Represents thread to the outside world.  This is the port that is returned by thread_self.

THREAD_SPECIAL_PORT_EXCEPTION
     Exception messages for task are sent to this port. See Exceptions.

There are some slots reserved for the future, and some that are free to be used by applications.

 -- Thread function: kern_return_t thread_special_port_set (rtmk_port_t THREAD, int SLOT, rtmk_port_t PORT)
     Set control port in THREAD to PORT at SLOT in control port array. (??? write something else here)

 -- Thread function: kern_return_t thread_special_port_get (rtmk_port_t THREAD, int SLOT, rtmk_port_t *PORTP)
     Get send rights to port SLOT in THREAD's control port set. Right is returned in PORTP.

Thread states
-------------

The thread_state_get and thread_state_set function are used to retrieve or set information about a particular thread.  The FLAVOR argument specifies what state/status we want.  Available flavors:

THREAD_STATE_FLAVOR_TIMING
     Timing information about thread. The thread_state_timing structure holds both user- and system-timing.  *COUNTP should be THREAD_STATE_FLAVOR_TIMING_COUNT.  This flavor is read only.

 -- Thread function: kern_return_t thread_state_get (rtmk_port_t THREAD, int FLAVOR, void *STATE, int *COUNTP)
     Get state specified with FLAVOR from THREAD.  State is returned in STATE.  *COUNTP should be the size of the state.  See above.

 -- Thread function: kern_return_t thread_state_set (rtmk_port_t THREAD, int FLAVOR, void *STATE, int COUNT)
     Set state specified with FLAVOR from THREAD.  STATE holds the state. COUNT should be the size of the state.  See above.

Setting priority
----------------

The rtmk microkernel provides three different scheduling policies and a 0-127 priority range per policy.  These are set per-thread.

THREAD_POLICY_TIMESHARE
     The default scheduling policy.  The threads are scheduled using a credit-based time sharing algorithm.

THREAD_POLICY_RR
     Threads are scheduled in a round-robin maner.

THREAD_POLICY_FIFO
THREAD_POLICY_FCFS
     A first come, first served scheduling algorithm.  Threads are only preempted by higher-priority threads.

 -- Thread function: kern_return_t thread_priority_set (rtmk_port_t THREAD, int POLICY, int PRIORITY)
     Set scheduling policy and priority for THREAD to POLICY and PRIORITY.  If POLICY is an unknown scheduling policy, or if PRIORITY is out of range, KERN_INVALID_ARGUMENT is returned.

Ports - The communication channel
=================================

A port is a simple communication channel -- implemented as a message queue managed and protected by the kernel.

A port set is a collection of ports that have a single protected message queue, which enables M:N communication with a single server.

Allocating ports
----------------

Ports and port sets are allocated with the same functions.

 -- Ports function: kern_return_t port_allocate (rtmk_port_t TASK, rtmk_port_right_t FLAVOR, rtmk_port_t *PORTP)
     Allocate receive right to a new port in TASK's protected name space. FLAVOR specifies what type of port right we should allocate, either RTMK_PORT_RIGHT_RECEIVE or RTMK_PORT_RIGHT_PORT_SET.

 -- Ports function: kern_return_t port_allocate_named (rtmk_port_t TASK, rtmk_port_right_t FLAVOR, rtmk_port_t PORT_NAME)
     Same things as port_allocate except that we don't let the kernel choose our right name. Instead we insist on the name PORT_NAME.

 -- Ports function: kern_return_t port_move_member (rtmk_port_t TASK, rtmk_port_t MEMBER, rtmk_port_t PSET)
     Insert MEMBER into port set specified by PSET.  If PSET is NULL, MEMBER is removed from any port set it was a member of.

Destroying ports
----------------

 -- Ports function: kern_return_t port_deallocate (rtmk_port_t TASK, rtmk_port_t PORT_NAME)
     Deallocate a reference to PORT_NAME.  If reference count drops to zero, the right is removed from TASK's protected name space.

 -- Ports function: kern_return_t port_destroy (rtmk_port_t TASK, rtmk_port_t PORT_NAME)
     Destroy PORT_NAME.  TASK must hold receive right to it, which can be either a port or a port set. After this, the port is considered dead and no more messages can be sent to it.

Migration control
-----------------

It is possible to forbid and permit threads from migrating into the targets context.  Threads that tries to migrate through a migrate inhibited target will block until migration is re-enabled.

 -- Ports function: kern_return_t port_inhibit (rtmk_port_t TASK, rtmk_port_t PORT_NAME)
     Inhibit migration to port or port set specified by PORT_NAME.

 -- Ports function: kern_return_t port_exhibit (rtmk_port_t TASK, rtmk_port_t PORT_NAME)
     Enable threads to migrate into TASK's context through PORT_NAME.

Sending and receiving messages
------------------------------

 -- Ports function: kern_return_t msg_send (struct rtmk_msg_header *MSGH, rtmk_msg_timeout_t TIMEOUT)
     Send message to msgh->msgh_remote_port.  MSGH is pointer to typed data.  If TIMEOUT is zero, we can block forever.

 -- Ports function: kern_return_t msg_receive (struct rtmk_msg_header *MSGH, rtmk_msg_timeout_t TIMEOUT)
     Receive message from local port specified in message header MSGH. If TIMEOUT is zero, we can block forever.

 -- Ports function: kern_return_t msg_rpc (struct rtmk_msg_header *MSGH, rtmk_msg_size_t RECV_SIZE, rtmk_msg_timeout_t TIMEOUT)
     Perform a full RPC from information in MSGH.  RECV_SIZE is length of receive buffer.  If TIMEOUT is zero, we can block forever.

 -- Ports function: kern_return_t msg_migrate (struct rtmk_msg_header *MSGH, rtmk_msg_size_t RECV_SIZE)
     Perform a full RPC with thread migration (the fast path).  RECV_SIZE is length of receive buffer.

Virtual memory management
=========================

 -- VM function: kern_return_t vm_allocate (rtmk_port_t TASK, vm_size_t SIZE, vm_offset_t *OFFSETP, int ANYWHERE_P)
     Allocate anonymous region of SIZE bytes in TASK's address space. If ANYWHERE_P is true the kernel chooses offset into address space, othersize *OFFSETP specifies location.  Offset is returned in OFFSETP.

 -- VM function: kern_return_t vm_deallocate (rtmk_port_t TASK, vm_offset_t OFFSET, vm_size_t SIZE)
     Deallocate region [OFFSET, OFFSET+SIZE) of TASK's address space.

 -- VM function: kern_return_t vm_protect (rtmk_port_t TASK, vm_offset_t OFFSET, vm_size_t SIZE, vm_prot_t PROTECTION)
     Lower protection level of region [OFFSET, OFFSET+SIZE) to PROTECTION.  If PROTECTION is higher than maximum protection, KERN_INVALID_ARGUMENT is returned.

Locking memory
--------------

For some applications it is neccesarry, to ensure real-time, to lock certain regions of the address space in memory.  Locked memory will never be swaped out.

 -- VM function: kern_return_t vm_wire (rtmk_port_t TASK, vm_offset_t OFFSET, vm_size_t SIZE, int WIRED_P)
     Lock region [OFFSET, OFFSET+SIZE) into memory if WIRED_P is true.  If user tries to lock a region into memory, and some pages were swaped-out, those are brought in before this function returns.

Mapping a memory object
-----------------------

 -- VM function: kern_return_t vm_map (rtmk_port_t TASK, rtmk_port_t MEMORY_OBJECT, vm_offset_t *OFFSETP, vm_size_t SIZE, int ANYWHERE_P, vm_prot_t PROT, vm_inherit_t INHERIT)
     Map SIZE bytes of MEMORY_OBJECT into TASK's address space. Kernel chooses offset into address space if ANYWHERE_P is true, othersize *OFFSETP specifies location. Offset is returned in OFFSETP.

Copying memory between tasks
----------------------------

Sometime it is neccessary to copy memory between different address spaces. This can be done by three functions; vm_write, vm_read and vm_copy.

??? wip!

Exception handling
==================

When a thread causes and exception, due to for example a divide by zero, an exception message is send to the threads exception port.  If the thread do not have an assigned port, it send it to the tasks port, of which the thread belongs to.

The message is in the form of a RPC, defined as following:

     (define-method exception_raise (returns REMS_MSG_TYPE_INTEGER32)
       (arguments (out exc_port  RTMK_MSG_TYPE_COPY_SEND)
                  (out thread    RTMK_MSG_TYPE_COPY_SEND)
                  (out task      RTMK_MSG_TYPE_COPY_SEND)
                  (out exception RTMK_MSG_TYPE_INTEGER32)
                  (out code      RTMK_MSG_TYPE_INTEGER32)
                  (out subcode   RTMK_MSG_TYPE_INTEGER32)
                  (out state     RTMK_MSG_TYPE_INTEGER8[]))
     )

EXC_PORT is the exception port that the message is sent to. THREAD is the thread that caused the exception, and the thread belongs to TASK.  EXCEPTION tells us what type of exception THREADS raised.  The value of CODE and SUBCODE is dependent on type of exception.  Exception types:

EXCEPTION_BAD_ACCESS
     Could not access memory. CODE contains kern_return_t describing error. CODE contains bad memory address.

EXCEPTION_BAD_INSN
     Instruction failed.  CODE contains address of bad instruction.

EXCEPTION_ARITHMETIC
     Arithmetic error. Exact nature of exception is in CODE.

EXCEPTION_SOFTWARE
     Exception caused by software. The value of CODE and SUBCODE is dependent on architecture.

EXCEPTION_BREAKPOINT
     Thread caused an breakpoint. The value of CODE and SUBCODE is dependent on architecture. (??? is this correct?)

Kernel error codes
==================

All kernel functions that returns a value of the kern_return_t type uses a set of standard error codes, that is listed here:

KERN_SUCCESS
     No error.

KERN_INVALID_ADDRESS
     Address specifed was not valid.

KERN_NO_SPACE
     No space in the virtual address space.

KERN_INVALID_ARGUMENT
     User passed an invalid argument to the kernel.

KERN_FAILURE
     General failure.  Kernel can not specify what went wrong.

KERN_RESOURCE_SHORTAGE
     The kernel ran out of resources while trying to perform the action. Normally this means that there no more memory, and the page-out daemon does not work as it should.

KERN_NOT_RECEIVER
     The task does not have receive rights for a specified port.

KERN_NO_ACCESS
     The task have no access to specified resource.

KERN_NOT_IN_SET
     Port is not a member of the specified port set.

KERN_NAME_EXISTS
     The specified right name already exist.

KERN_RIGHT_EXISTS
     The specified right already existed.

KERN_ABORTED
     The system call was aborted.

KERN_INVALID_NAME
     The name that was specifed was invalid.

KERN_INVALID_TASK
     The task that was specifed was invalid.

KERN_INVALID_HOST
     The host that was specifed was invalid.

KERN_INVALID_RIGHT
     The right that was specified was invalid.

KERN_INVALID_VALUE
     The value was invalid.