WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH 1/1] Xen ARINC 653 Scheduler (updated to add support

To: <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH 1/1] Xen ARINC 653 Scheduler (updated to add support for CPU pools)
From: "Kathy Hadley" <Kathy.Hadley@xxxxxxxxxxxxxxx>
Date: Wed, 16 Jun 2010 11:04:04 -0400
Cc: George Dunlap <dunlapg@xxxxxxxxx>, Keir Fraser <keir.fraser@xxxxxxxxxxxxx>
Delivery-date: Wed, 16 Jun 2010 08:07:09 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
Thread-index: AcsNZSkdroPbUMSvSOWCqVW92EbfPw==
Thread-topic: [Xen-devel] [PATCH 1/1] Xen ARINC 653 Scheduler (updated to add support for CPU pools)

This patch adds an ARINC 653 scheduler to Xen.  This is a modification of an earlier patch (submitted Friday, April 16).  In particular, it has been modified to use the new .adjust_global callback function (added by Keir Fraser in c/s 21282) and to support CPU pools (per feedback received from George Dunlap on Tuesday, May 4).

 

Thanks and regards,

  Kathy Hadley

  DornerWorks, Ltd.

 

 

diff -rupN a/tools/libxc/Makefile b/tools/libxc/Makefile

--- a/tools/libxc/Makefile 2010-05-26 17:01:34.000000000 -0400

+++ b/tools/libxc/Makefile 2010-06-01 12:30:45.000000000 -0400

@@ -19,6 +19,7 @@ CTRL_SRCS-y       += xc_private.c

 CTRL_SRCS-y       += xc_sedf.c

 CTRL_SRCS-y       += xc_csched.c

 CTRL_SRCS-y       += xc_csched2.c

+CTRL_SRCS-y       += xc_arinc653.c

 CTRL_SRCS-y       += xc_tbuf.c

 CTRL_SRCS-y       += xc_pm.c

 CTRL_SRCS-y       += xc_cpu_hotplug.c

diff -rupN a/tools/libxc/xc_arinc653.c b/tools/libxc/xc_arinc653.c

--- a/tools/libxc/xc_arinc653.c 1969-12-31 19:00:00.000000000 -0500

+++ b/tools/libxc/xc_arinc653.c 2010-06-14 10:50:57.000000000 -0400

@@ -0,0 +1,27 @@

+/****************************************************************************

+ * (C) 2010 - DornerWorks, Ltd <DornerWorks.com>

+ ****************************************************************************

+ *

+ *        File: xc_arinc653.c

+ *      Author: Josh Holtrop <DornerWorks.com>

+ *

+ * Description: XC Interface to the ARINC 653 scheduler

+ *

+ */

+

+#include "xc_private.h"

+

+int

+xc_sched_arinc653_sched_set(

+    int xc_handle,

+    xen_sysctl_sched_arinc653_schedule_t * sched)

+{

+    DECLARE_SYSCTL;

+

+    sysctl.cmd = XEN_SYSCTL_scheduler_op;

+    sysctl.u.scheduler_op.sched_id = XEN_SCHEDULER_ARINC653;

+    sysctl.u.scheduler_op.cmd = XEN_SYSCTL_SCHEDOP_putinfo;

+    set_xen_guest_handle(sysctl.u.scheduler_op.u.arinc653.schedule, sched);

+

+    return do_sysctl(xc_handle, &sysctl);

+}

diff -rupN a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h

--- a/tools/libxc/xenctrl.h     2010-05-26 17:01:34.000000000 -0400

+++ b/tools/libxc/xenctrl.h     2010-06-01 12:30:45.000000000 -0400

@@ -485,6 +485,16 @@ int xc_sched_credit2_domain_get(int xc_h

                                struct xen_domctl_sched_credit2 *sdom);

 

 /**

+ * This function sets the global ARINC 653 schedule.

+ *

+ * @parm xc_handle a handle to an open hypervisor interface

+ * @parm sched a pointer to the new ARINC 653 schedule

+ * return 0 on success

+ */

+int xc_sched_arinc653_sched_set(int xc_handle,

+                                xen_sysctl_sched_arinc653_schedule_t * sched);

+

+/**

  * This function sends a trigger to a domain.

  *

  * @parm xc_handle a handle to an open hypervisor interface

diff -rupN a/xen/common/Makefile b/xen/common/Makefile

--- a/xen/common/Makefile  2010-05-26 17:01:34.000000000 -0400

+++ b/xen/common/Makefile  2010-06-01 12:30:45.000000000 -0400

@@ -17,6 +17,7 @@ obj-y += rangeset.o

 obj-y += sched_credit.o

 obj-y += sched_credit2.o

 obj-y += sched_sedf.o

+obj-y += sched_arinc653.o

 obj-y += schedule.o

 obj-y += shutdown.o

 obj-y += softirq.o

diff -rupN a/xen/common/sched_arinc653.c b/xen/common/sched_arinc653.c

--- a/xen/common/sched_arinc653.c    1969-12-31 19:00:00.000000000 -0500

+++ b/xen/common/sched_arinc653.c    2010-06-16 09:05:24.000000000 -0400

@@ -0,0 +1,806 @@

+/*

+ * File: sched_arinc653.c

+ * Copyright (c) 2010, DornerWorks, Ltd. <DornerWorks.com>

+ *

+ * Description:

+ *   This file provides an ARINC 653-compatible scheduling algorithm

+ *   for use in Xen.

+ *

+ * This program is free software; you can redistribute it and/or modify it

+ * under the terms of the GNU General Public License as published by the Free

+ * software Foundation; either version 2 of the License, or (at your option)

+ * any later version.

+ *

+ * This program is distributed in the hope that it will be useful,

+ * but WITHOUT ANY WARRANTY; without even the implied warranty of

+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

+ * See the GNU General Public License for more details.

+ */

+

+

+/**************************************************************************

+ * Includes                                                               *

+ *************************************************************************/

+#include <xen/lib.h>

+#include <xen/sched.h>

+#include <xen/sched-if.h>

+#include <xen/timer.h>

+#include <xen/softirq.h>

+#include <xen/time.h>

+#include <xen/errno.h>

+#include <xen/list.h>

+#include <public/sysctl.h>          /* ARINC653_MAX_DOMAINS_PER_SCHEDULE */

+#include <xen/guest_access.h>

+

+

+/**************************************************************************

+ * Private Macros                                                         *

+ **************************************************************************/

+

+/**

+ * Retrieve the idle VCPU for a given physical CPU

+ */

+#define IDLETASK(cpu)  (idle_vcpu[cpu])

+

+/**

+ * Return a pointer to the ARINC 653-specific scheduler data information

+ * associated with the given VCPU (vc)

+ */

+#define AVCPU(vc) ((arinc653_vcpu_t *)(vc)->sched_priv)

+

+

+/**************************************************************************

+ * Private Type Definitions                                               *

+ **************************************************************************/

+

+/**

+ * The sched_entry_t structure holds a single entry of the

+ * ARINC 653 schedule.

+ */

+typedef struct sched_entry_s

+{

+    /* dom_handle holds the handle ("UUID") for the domain that this

+     * schedule entry refers to. */

+    xen_domain_handle_t dom_handle;

+    /* vcpu_id holds the VCPU number for the VCPU that this schedule

+     * entry refers to. */

+    int                 vcpu_id;

+    /* runtime holds the number of nanoseconds that the VCPU for this

+     * schedule entry should be allowed to run per major frame. */

+    s_time_t            runtime;

+    /* vc holds a pointer to the Xen VCPU structure */

+    struct vcpu *       vc;

+} sched_entry_t;

+

+/**

+ * The arinc653_vcpu_t structure holds ARINC 653-scheduler-specific

+ * information for all non-idle VCPUs

+ */

+typedef struct arinc653_vcpu_s

+{

+    /* vc points to Xen's struct vcpu so we can get to it from an

+     * arinc653_vcpu_t pointer. */

+    struct vcpu *       vc;

+    /* awake holds whether the VCPU has been woken with vcpu_wake() */

+    bool_t              awake;

+    /* list holds the linked list information for the list this VCPU

+     * is stored in */

+    struct list_head    list;

+} arinc653_vcpu_t;

+

+/**

+ * Data structure containing domain-specific information.

+ */

+struct arinc653_dom_info {

+    struct domain  *domain;

+};

+

+/**

+ * Data structure containing all the "global" data items used by the scheduler.

+ */

+typedef struct arinc653_sched_private_s

+{

+    /*

+     * This array holds the active ARINC 653 schedule.

+     *

+     * When the system tries to start a new VCPU, this schedule is scanned

+     * to look for a matching (handle, VCPU #) pair. If both the handle ("UUID")

+     * and VCPU number match, then the VCPU is allowed to run. Its run time

+     * (per major frame) is given in the third entry of the schedule.

+     */

+    sched_entry_t arinc653_schedule[ARINC653_MAX_DOMAINS_PER_SCHEDULE];

+    /*

+     * This variable holds the number of entries that are valid in

+     * the arinc653_schedule table.

+     *

+     * This is not necessarily the same as the number of domains in the

+     * schedule. A domain could be listed multiple times within the schedule,

+     * or a domain with multiple VCPUs could have a different

+     * schedule entry for each VCPU.

+     *

+     * A value of 1 means that only 1 domain (Dom0) will initially be started.

+     */

+    int num_schedule_entries;

+    /*

+     * arinc653_major_frame holds the major frame time for the ARINC 653

+     * schedule.

+     */

+    s_time_t arinc653_major_frame;

+    /*

+     * next_major_frame holds the time that the next major frame starts

+     */

+    s_time_t next_major_frame;

+    /*

+     * vcpu_list holds pointers to all Xen VCPU structures for iterating through

+     */

+    struct list_head vcpu_list;

+} arinc653_sched_private_t;

+

+

+/**************************************************************************

+ * Global data                                                            *

+ **************************************************************************/

+static arinc653_sched_private_t arinc653_schedule;

+

+

+/**************************************************************************

+ * Scheduler functions                                                    *

+ **************************************************************************/

+

+/**

+ * This function compares two domain handles.

+ *

+ * @param h1        Pointer to handle 1

+ * @param h2        Pointer to handle 2

+ *

+ * @return          <ul>

+ *                  <li> <0:  handle 1 is less than handle 2

+ *                  <li>  0:  handle 1 is equal to handle 2

+ *                  <li> >0:  handle 1 is greater than handle 2

+ *                  </ul>

+ */

+static int dom_handle_cmp(const xen_domain_handle_t h1,

+                          const xen_domain_handle_t h2)

+{

+    return memcmp(h1, h2, sizeof(xen_domain_handle_t));

+} /* end dom_handle_cmp */

+

+/**

+ * This function searches the vcpu list to find a VCPU that matches

+ * the domain handle and VCPU ID specified.

+ *

+ * @param ops       Pointer to data structure with data & functions for the

+ *                  current scheduler

+ * @param handle    Pointer to handle

+ * @param vcpu_id   VCPU ID

+ *

+ * @return          <ul>

+ *                  <li> Pointer to the matching VCPU if one is found

+ *                  <li> NULL otherwise

+ *                  </ul>

+ */

+static struct vcpu * find_vcpu(const struct scheduler *ops,

+                               xen_domain_handle_t handle,

+                               int vcpu_id)

+{

+    arinc653_sched_private_t *prv = ops->sched_data;

+    arinc653_vcpu_t * avcpu; /* loop index variable */

+    struct vcpu * vc = NULL;

+

+    /* loop through the vcpu_list looking for the specified VCPU */

+    list_for_each_entry(avcpu, &prv->vcpu_list, list)

+    {

+        /* If the handles & VCPU IDs match, we've found a matching VCPU */

+        if ((dom_handle_cmp(avcpu->vc->domain->handle, handle) == 0)

+             && (vcpu_id == avcpu->vc->vcpu_id))

+        {

+            vc = avcpu->vc;

+            /*

+             * "break" statement used instead of loop control variable because

+             * the macro used for this loop does not support using loop control

+             * variables

+             */

+            break;

+        }

+    }

+

+    return vc;

+} /* end find_vcpu */

+

+/**

+ * This function updates the pointer to the Xen VCPU structure for each entry in

+ * the ARINC 653 schedule.

+ *

+ * @param ops       Pointer to data structure with data & functions for the

+ *                  current scheduler

+ *

+ * @return <None>

+ */

+static void update_schedule_vcpus(const struct scheduler *ops)

+{

+    arinc653_sched_private_t *prv = ops->sched_data;

+

+    /* Loop through the number of entries in the schedule */

+    for (int i = 0; i < prv->num_schedule_entries; i++)

+    {

+        /* Update the pointer to the Xen VCPU structure for the current entry */

+        prv->arinc653_schedule[i].vc =

+            find_vcpu(ops,

+                      prv->arinc653_schedule[i].dom_handle,

+                      prv->arinc653_schedule[i].vcpu_id);

+    }

+} /* end update_schedule_vcpus */

+

+/**

+ * This function is called by the arinc653_adjust_global scheduler

+ * callback function in response to a domain control hypercall with

+ * a scheduler operation.

+ *

+ * The parameter schedule is set to be the address of a local variable from

+ * within arinc653_adjust_global(), so it is guaranteed to not be NULL.

+ *

+ * @param ops       Pointer to data structure with data & functions for the

+ *                  current scheduler

+ * @param schedule  Pointer to the new ARINC 653 schedule.

+ *

+ * @return          <ul>

+ *                  <li> 0 = success

+ *                  <li> !0 = error

+ *                  </ul>

+ */

+static int arinc653_sched_set(const struct scheduler *ops,

+                              xen_sysctl_sched_arinc653_schedule_t * schedule)

+{

+    arinc653_sched_private_t *prv = ops->sched_data;

+

+    int ret = 0;

+    s_time_t total_runtime = 0;

+    bool_t found_dom0 = 0;

+    const static xen_domain_handle_t dom0_handle = {0};

+

+    /* check for valid major frame and number of schedule entries */

+    if ( (schedule->major_frame <= 0)

+      || (schedule->num_sched_entries < 1)

+      || (schedule->num_sched_entries > ARINC653_MAX_DOMAINS_PER_SCHEDULE) )

+    {

+        ret = -EINVAL;

+    }

+

+    if (ret == 0)

+    {

+        for (int i = 0; i < schedule->num_sched_entries; i++)

+        {

+            /*

+             * look for domain 0 handle - every schedule must contain

+             * some time for domain 0 to run

+             */

+            if (dom_handle_cmp(schedule->sched_entries[i].dom_handle,

+                               dom0_handle) == 0)

+            {

+                found_dom0 = 1;

+            }

+

+            /* check for a valid VCPU ID and run time */

+            if ( (schedule->sched_entries[i].vcpu_id < 0)

+              || (schedule->sched_entries[i].runtime <= 0) )

+            {

+                ret = -EINVAL;

+            }

+            else

+            {

+                /* Add this entry's run time to total run time */

+                total_runtime += schedule->sched_entries[i].runtime;

+            }

+        } /* end loop through schedule entries */

+    }

+

+    if (ret == 0)

+    {

+        /* error if the schedule doesn't contain a slot for domain 0 */

+        if (found_dom0 == 0)

+        {

+            ret = -EINVAL;

+        }

+    }

+

+    if (ret == 0)

+    {

+        /*

+         * error if the major frame is not large enough to run all entries

+         * as indicated by comparing the total run time to the major frame

+         * length

+         */

+        if (total_runtime > schedule->major_frame)

+        {

+            ret = -EINVAL;

+        }

+    }

+

+    if (ret == 0)

+    {

+        /* copy the new schedule into place */

+        prv->num_schedule_entries = schedule->num_sched_entries;

+        prv->arinc653_major_frame = schedule->major_frame;

+        for (int i = 0; i < prv->num_schedule_entries; i++)

+        {

+            memcpy(prv->arinc653_schedule[i].dom_handle,

+                   schedule->sched_entries[i].dom_handle,

+                   sizeof(prv->arinc653_schedule[i].dom_handle));

+            prv->arinc653_schedule[i].vcpu_id =

+                schedule->sched_entries[i].vcpu_id;

+            prv->arinc653_schedule[i].runtime =

+                schedule->sched_entries[i].runtime;

+        }

+        update_schedule_vcpus(ops);

+

+        /*

+         * The newly-installed schedule takes effect immediately.

+         * We do not even wait for the current major frame to expire.

+         *

+         * Signal a new major frame to begin. The next major frame

+         * is set up by the do_schedule callback function when it

+         * is next invoked.

+         */

+        prv->next_major_frame = NOW();

+    }

+

+    return ret;

+} /* end arinc653_sched_set */

+

+/**

+ * Xen scheduler callback function to adjust global scheduling parameters

+ *

+ * @param ops       Pointer to data structure with data & functions for the

+ *                  current scheduler

+ * @param op        Pointer to the system control scheduler operation structure

+ *

+ * @return          <ul>

+ *                  <li> 0 = success

+ *                  <li> !0 = error

+ *                  </ul>

+ */

+static int arinc653_adjust_global(const struct scheduler *ops,

+                                  struct xen_sysctl_scheduler_op * op)

+{

+    int ret = -1;

+    xen_sysctl_sched_arinc653_schedule_t new_sched;

+

+    if (op->cmd == XEN_SYSCTL_SCHEDOP_putinfo)

+    {

+        if (copy_from_guest(&new_sched, op->u.arinc653.schedule, 1) != 0)

+        {

+            ret = -EFAULT;

+        }

+        else

+        {

+            ret = arinc653_sched_set(ops, &new_sched);

+        }

+    }

+

+    return ret;

+} /* end arinc653_adjust_global */

+

+/**

+ * Xen scheduler callback function to allocate and initialize the ARINC 653

+ * scheduler data structure.

+ *

+ * @param ops       Pointer to data structure with data & functions for the

+ *                  current scheduler

+ * @param pool0     Flag indicating whether pool 0 or other being allocated

+ *                  [Not Used]

+ *

+ * @return          <ul>

+ *                  <li> 0 = success

+ *                  <li> !0 = error

+ *                  </ul>

+ */

+static int arinc653_init(struct scheduler *ops)

+{

+    arinc653_sched_private_t *prv;

+    int i;

+

+    /* Initial value for the ARINC 653 scheduler data.*/

+    const sched_entry_t init_sched_element = { "", 0, MILLISECS(10), NULL };

+

+    /* Allocate memory for ARINC 653 scheduler data structure */

+    prv = &arinc653_schedule;

+    if ( prv == NULL )

+    {

+        return -ENOMEM;

+    }

+

+    /* Initialize the ARINC 653 scheduler data structure*/

+    memset(prv, 0, sizeof(*prv));

+

+    /* Set the "scheduler" structure to point to the ARINC 653 scheduler data */

+    ops->sched_data = prv;

+

+    /*

+     * Initialize the ARINC 653 scheduler data.  In particular:

+     *   All domains execute for 10 ms.

+     *   Only one domain is enabled (domain 0).

+     *   Major frame = 10 ms (time required for domain 0).

+     */

+    for (i=0; i<(sizeof(prv->arinc653_schedule)/sizeof(sched_entry_t)); i++)

+    {

+        prv->arinc653_schedule[i] = init_sched_element;

+    }

+    prv->num_schedule_entries = 1;

+    prv->arinc653_major_frame = MILLISECS(10);

+    prv->next_major_frame = 0;

+    INIT_LIST_HEAD(&prv->vcpu_list);

+

+    return 0;

+} /* end arinc653_init */

+

+/**

+ * Xen scheduler callback function to allocate and initialize a data structure

+ * containing information for a VCPU.

+ *

+ * @param ops       Pointer to data structure with data & functions for the

+ *                  current scheduler

+ * @param v         Pointer to the VCPU structure

+ * @param dd        Domain data [Not Used]

+ *

+ * @return          <ul>

+ *                  <li> address of the allocated data structure

+ *                  <li> NULL if error

+ *                  </ul>

+ */

+static void *arinc653_alloc_vdata(const struct scheduler *ops,

+                                  struct vcpu *v,

+                                  void *dd)

+{

+    arinc653_sched_private_t *prv = ops->sched_data;

+    arinc653_vcpu_t *inf;

+

+    /*

+     * Allocate memory for the ARINC 653-specific scheduler data information

+     * associated with the given VCPU (vc).

+     */

+    inf = xmalloc(arinc653_vcpu_t);

+    if (inf != NULL)

+    {

+        /*

+         * Initialize our ARINC 653 scheduler-specific information

+         * for the VCPU.

+         * The VCPU starts "asleep."

+         * When Xen is ready for the VCPU to run, it will call

+         * the vcpu_wake scheduler callback function and our

+         * scheduler will mark the VCPU awake.

+         */

+        inf->vc = v;

+        inf->awake = 0;

+        list_add(&inf->list, &prv->vcpu_list);

+        update_schedule_vcpus(ops);

+    }

+

+    return inf;

+} /* end arinc653_alloc_vdata */

+

+/**

+ * Xen scheduler callback function to free up VCPU data.

+ *

+ * @param ops       Pointer to data structure with data & functions for the

+ *                  current scheduler [Not Used]

+ * @param priv      Pointer to the VCPU structure

+ *

+ * @return          <None>

+ */

+static void arinc653_free_vdata(const struct scheduler *ops, void *priv)

+{

+    /* Free the arinc653_vcpu structure */

+    xfree(AVCPU((struct vcpu *)priv));

+} /* end arinc653_free_vdata */

+

+/**

+ * Xen scheduler callback function to allocate and initialize a data structure

+ * containing domain-specific data.

+ *

+ * @param ops       Pointer to data structure with data & functions for the

+ *                  current scheduler [Not Used]

+ * @param dom       Pointer to data structure with data for the current domain

+ *                  [Not Used]

+ *

+ * @return void*    <ul>

+ *                  <li> address of the allocated data structure

+ *                  </ul>

+ */

+static void *

+arinc653_alloc_domdata(const struct scheduler *ops, struct domain *dom)

+{

+    void *mem;

+

+    /* Allocate memory for the domain-specific data structure */

+    mem = xmalloc(struct arinc653_dom_info);

+    if ( mem == NULL )

+    {

+        return NULL;

+    }

+

+    /* Initialize the allocated memory */

+    memset(mem, 0, sizeof(struct arinc653_dom_info));

+

+    return mem;

+} /* end arinc653_alloc_domdata */

+

+/**

+ * Xen scheduler callback function to free up domain-specific data.

+ *

+ * @param ops       Pointer to data structure with data & functions for the

+ *                  current scheduler [Not Used]

+ * @param data      Pointer to the domain-specific data structure

+ *

+ * @return          <None>

+ */

+static void arinc653_free_domdata(const struct scheduler *ops, void *data)

+{

+    /* free the domain-specific data structure */

+    xfree(data);

+} /* end arinc653_free_domdata */

+

+/**

+ * Xen scheduler callback function to initialize a domain.

+ *

+ * @param ops       Pointer to data structure with data & functions for the

+ *                  current scheduler [Not Used]

+ * @param dom       Pointer to domain-specific data structure

+ *

+ * @return int      <ul>

+ *                  <li> 0 for success

+ *                  <li> -ENOMEM if out of memory

+ *                  </ul>

+ */

+static int arinc653_init_domain(const struct scheduler *ops,

+                                struct domain *dom)

+{

+    /* Don't allocate a data structure for an idle domain */

+    if ( is_idle_domain(dom) )

+    {

+        return 0;

+    }

+

+    /* Allocate memory for the domain. */

+    dom->sched_priv = arinc653_alloc_domdata(ops, dom);

+    if ( dom->sched_priv == NULL )

+    {

+        return -ENOMEM;

+    }

+

+    return 0;

+} /* end arinc653_init_domain */

+

+/**

+ * Xen scheduler callback function to destroy a domain.

+ *

+ * @param ops       Pointer to data structure with data & functions for the

+ *                  current scheduler

+ * @param dom       Pointer to domain-specific data structure

+ */

+static void arinc653_destroy_domain(const struct scheduler *ops,

+                                    struct domain *dom)

+{

+    arinc653_free_domdata(ops, dom->sched_priv);

+} /* end arinc653_destroy_domain */

+

+/**

+ * Xen scheduler callback function to remove a VCPU.

+ *

+ * @param ops       Pointer to data structure with data & functions for the

+ *                  current scheduler

+ * @param v         Pointer to the VCPU structure to remove

+ *

+ * @return          <None>

+ */

+static void arinc653_destroy_vcpu(const struct scheduler *ops, struct vcpu * v)

+{

+    if (AVCPU(v) != NULL)

+    {

+        /* remove the VCPU from whichever list it is on */

+        list_del(&AVCPU(v)->list);

+        /* free the arinc653_vcpu structure */

+        arinc653_free_vdata(ops, v);

+        update_schedule_vcpus(ops);

+    }

+} /* end arinc653_destroy_vcpu */

+

+/**

+ * Xen scheduler callback function to select a VCPU to run.

+ * This is the main scheduler routine.

+ *

+ * @param ops       Pointer to data structure with data & functions for the

+ *                  current scheduler

+ * @param t         Current time

+ * @param tasklet_work_scheduled

+ *                  [Not Used]

+ *

+ * @return          Time slice and address of the VCPU structure for the chosen

+ *                  domain

+ */

+static struct task_slice arinc653_do_schedule(const struct scheduler *ops,

+                                              s_time_t t,

+                                              bool_t tasklet_work_scheduled)

+{

+    arinc653_sched_private_t *prv = ops->sched_data;

+

+    struct task_slice ret;                      /* hold the chosen domain */

+    struct vcpu * new_task = NULL;

+    static int sched_index = 0;

+    static s_time_t last_major_frame;

+    static s_time_t last_switch_time;

+    static s_time_t next_switch_time;

+

+    if (t >= prv->next_major_frame)

+    {

+        /* time to enter a new major frame

+         * the first time this function is called, this will be true */

+        sched_index = 0;

+        last_major_frame = last_switch_time = t;

+        prv->next_major_frame = t + prv->arinc653_major_frame;

+    }

+    else if (t >= next_switch_time)

+    {

+        /* time to switch to the next domain in this major frame */

+        sched_index++;

+        last_switch_time = next_switch_time;

+    }

+

+    /*

+     * If there are more domains to run in the current major frame, set

+     * next_switch_time equal to the last switch time + this domain's run time.

+     * Otherwise, set next_switch_time equal to the start of the next major

+     * frame.

+     */

+    next_switch_time = (sched_index < prv->num_schedule_entries)

+        ? last_switch_time + prv->arinc653_schedule[sched_index].runtime

+        : prv->next_major_frame;

+

+    /*

+     * If there are more domains to run in the current major frame, set

+     * new_task equal to the address of next domain's VCPU structure.

+     * Otherwise, set new_task equal to the address of the idle task's VCPU

+     * structure.

+     */

+    new_task = (sched_index < prv->num_schedule_entries)

+                   ? prv->arinc653_schedule[sched_index].vc

+                   : IDLETASK(0);

+

+    /* Check to see if the new task can be run (awake & runnable). */

+    if (!((new_task != NULL)

+            && AVCPU(new_task)->awake

+            && vcpu_runnable(new_task)) )

+    {

+        new_task = IDLETASK(0);

+    }

+    BUG_ON(new_task == NULL);

+

+    /*

+     * Check to make sure we did not miss a major frame.

+     * This is a good test for robust partitioning.

+     */

+    BUG_ON(t >= prv->next_major_frame);

+

+    /*

+     * Return the amount of time the next domain has to run and the address

+     * of the selected task's VCPU structure.

+     */

+    ret.time = next_switch_time - t;

+    ret.task = new_task;

+

+    BUG_ON(ret.time <= 0);

+

+    return ret;

+} /* end arinc653_do_schedule */

+

+/**

+ * Xen scheduler callback function to select a CPU for the VCPU to run on.

+ * Currently only one CPU is supported.

+ *

+ * @param ops       Pointer to data structure with data & functions for the

+ *                  current scheduler

+ * @param v         Pointer to the VCPU structure for the current domain

+ *

+ * @return          Number of selected physical CPU

+ */

+static int arinc653_pick_cpu(const struct scheduler *ops, struct vcpu *v)

+{

+    /* this implementation only supports one physical CPU */

+    return 0;

+} /* end arinc653_pick_cpu */

+

+/**

+ * Xen scheduler callback function to wake up a VCPU

+ *

+ * @param ops       Pointer to data structure with data & functions for the

+ *                  current scheduler [Not Used]

+ * @param vc        Pointer to the VCPU structure for the current domain

+ *

+ * @return          <None>

+ */

+static void arinc653_vcpu_wake(const struct scheduler *ops, struct vcpu *vc)

+{

+    /* boolean flag to indicate first run */

+    static bool_t dont_raise_softirq = 0;

+

+    if (AVCPU(vc) != NULL)  /* check that this is a VCPU we are tracking */

+    {

+        AVCPU(vc)->awake = 1;

+    }

+

+    /* the first time the vcpu_wake function is called, we should raise

+     * a softirq to invoke the do_scheduler callback */

+    if (!dont_raise_softirq)

+    {

+        cpu_raise_softirq(vc->processor, SCHEDULE_SOFTIRQ);

+        dont_raise_softirq = 1;

+    }

+} /* end arinc653_vcpu_wake */

+

+/**

+ * Xen scheduler callback function to sleep a VCPU

+ *

+ * @param ops       Pointer to data structure with data & functions for the

+ *                  current scheduler [Not Used]

+ * @param vc        Pointer to the VCPU structure for the current domain

+ *

+ * @return          <None>

+ */

+static void arinc653_vcpu_sleep(const struct scheduler *ops, struct vcpu *vc)

+{

+    if (AVCPU(vc) != NULL)  /* check that this is a VCPU we are tracking */

+    {

+        AVCPU(vc)->awake = 0;

+    }

+

+    /* if the VCPU being put to sleep is the same one that is currently

+     * running, raise a softirq to invoke the scheduler to switch domains */

+    if (per_cpu(schedule_data, vc->processor).curr == vc)

+    {

+        cpu_raise_softirq(vc->processor, SCHEDULE_SOFTIRQ);

+    }

+} /* end arinc653_vcpu_sleep */

+

+/**

+ * This structure defines our scheduler for Xen.

+ * The entries tell Xen where to find our scheduler-specific

+ * callback functions.

+ * The symbol must be visible to the rest of Xen at link time.

+ */

+struct scheduler sched_arinc653_def = {

+    .name           = "ARINC 653 Scheduler",

+    .opt_name       = "arinc653",

+    .sched_id       = XEN_SCHEDULER_ARINC653,

+    .sched_data     = &arinc653_schedule,

+

+    .init           = arinc653_init,

+/*  .deinit         = NULL, */

+

+    .free_vdata     = arinc653_free_vdata,

+    .alloc_vdata    = arinc653_alloc_vdata,

+

+/*  .free_pdata     = NULL, */

+/*  .alloc_pdata    = NULL, */

+    .free_domdata   = arinc653_free_domdata,

+    .alloc_domdata  = arinc653_alloc_domdata,

+

+    .init_domain    = arinc653_init_domain,

+    .destroy_domain = arinc653_destroy_domain,

+

+/*  .insert_vcpu    = NULL, */

+    .destroy_vcpu   = arinc653_destroy_vcpu,

+

+    .sleep          = arinc653_vcpu_sleep,

+    .wake           = arinc653_vcpu_wake,

+/*  .context_saved  = NULL, */

+

+    .do_schedule    = arinc653_do_schedule,

+

+    .pick_cpu       = arinc653_pick_cpu,

+/*  .adjust         = NULL, */

+    .adjust_global  = arinc653_adjust_global,

+/*  .dump_settings  = NULL, */

+/*  .dump_cpu_state = NULL, */

+

+/*  .tick_suspend   = NULL, */

+/*  .tick_resume    = NULL, */

+};

diff -rupN a/xen/common/schedule.c b/xen/common/schedule.c

--- a/xen/common/schedule.c     2010-05-26 17:01:34.000000000 -0400

+++ b/xen/common/schedule.c     2010-06-01 12:30:45.000000000 -0400

@@ -8,6 +8,8 @@

  *      Author: Rolf Neugebauer & Keir Fraser

  *              Updated for generic API by Mark Williamson

  *

+ *              ARINC 653 scheduler added by DornerWorks <DornerWorks.com>

+ *

  * Description: Generic CPU scheduling code

  *              implements support functionality for the Xen scheduler API.

  *

@@ -59,10 +61,12 @@ DEFINE_PER_CPU(struct scheduler *, sched

 extern const struct scheduler sched_sedf_def;

 extern const struct scheduler sched_credit_def;

 extern const struct scheduler sched_credit2_def;

+extern const struct scheduler sched_arinc653_def;

 static const struct scheduler *schedulers[] = {

     &sched_sedf_def,

     &sched_credit_def,

     &sched_credit2_def,

+    &sched_arinc653_def,

     NULL

 };

 

diff -rupN a/xen/include/public/domctl.h b/xen/include/public/domctl.h

--- a/xen/include/public/domctl.h    2010-05-26 17:01:34.000000000 -0400

+++ b/xen/include/public/domctl.h    2010-06-01 12:30:45.000000000 -0400

@@ -305,6 +305,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_max_v

 #define XEN_SCHEDULER_SEDF     4

 #define XEN_SCHEDULER_CREDIT   5

 #define XEN_SCHEDULER_CREDIT2  6

+#define XEN_SCHEDULER_ARINC653 7

 /* Set or get info? */

 #define XEN_DOMCTL_SCHEDOP_putinfo 0

 #define XEN_DOMCTL_SCHEDOP_getinfo 1

diff -rupN a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h

--- a/xen/include/public/sysctl.h    2010-05-26 17:01:34.000000000 -0400

+++ b/xen/include/public/sysctl.h    2010-06-01 12:30:45.000000000 -0400

@@ -22,6 +22,8 @@

  * DEALINGS IN THE SOFTWARE.

  *

  * Copyright (c) 2002-2006, K Fraser

+ *

+ * ARINC 653 Scheduler type added by DornerWorks <DornerWorks.com>.

  */

 

 #ifndef __XEN_PUBLIC_SYSCTL_H__

@@ -539,10 +541,43 @@ DEFINE_XEN_GUEST_HANDLE(xen_sysctl_cpupo

 /* Set or get info? */

 #define XEN_SYSCTL_SCHEDOP_putinfo 0

 #define XEN_SYSCTL_SCHEDOP_getinfo 1

+

+/*

+ * This structure is used to pass a new ARINC 653 schedule from a

+ * privileged domain (i.e. Dom0) to Xen.

+ */

+#define ARINC653_MAX_DOMAINS_PER_SCHEDULE   64

+struct xen_sysctl_sched_arinc653_schedule {

+    /* major_frame holds the time for the new schedule's major frame

+     * in nanoseconds. */

+    int64_t     major_frame;

+    /* num_sched_entries holds how many of the entries in the

+     * sched_entries[] array are valid. */

+    uint8_t     num_sched_entries;

+    /* The sched_entries array holds the actual schedule entries. */

+    struct {

+        /* dom_handle must match a domain's UUID */

+        xen_domain_handle_t dom_handle;

+        /* If a domain has multiple VCPUs, vcpu_id specifies which one

+         * this schedule entry applies to. It should be set to 0 if

+         * there is only one VCPU for the domain. */

+        int                 vcpu_id;

+        /* runtime specifies the amount of time that should be allocated

+         * to this VCPU per major frame. It is specified in nanoseconds */

+        int64_t             runtime;

+    } sched_entries[ARINC653_MAX_DOMAINS_PER_SCHEDULE];

+};

+typedef struct xen_sysctl_sched_arinc653_schedule

+    xen_sysctl_sched_arinc653_schedule_t;

+DEFINE_XEN_GUEST_HANDLE(xen_sysctl_sched_arinc653_schedule_t);

+

 struct xen_sysctl_scheduler_op {

     uint32_t sched_id;  /* XEN_SCHEDULER_* (domctl.h) */

     uint32_t cmd;       /* XEN_SYSCTL_SCHEDOP_* */

     union {

+        struct xen_sysctl_sched_arinc653 {

+            XEN_GUEST_HANDLE(xen_sysctl_sched_arinc653_schedule_t) schedule;

+        } arinc653;

     } u;

 };

 typedef struct xen_sysctl_scheduler_op xen_sysctl_scheduler_op_t;

Attachment: dornerworks-xen-4.1-arinc653-scheduler.patch
Description: dornerworks-xen-4.1-arinc653-scheduler.patch

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel