diff -r c0c1f5f0745e -r 5a4c3a1b488d tools/libxc/Makefile --- a/tools/libxc/Makefile Mon Nov 22 19:16:34 2010 +0000 +++ b/tools/libxc/Makefile Tue Nov 23 16:43:01 2010 -0500 @@ -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 -r c0c1f5f0745e -r 5a4c3a1b488d tools/libxc/xc_arinc653.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/libxc/xc_arinc653.c Tue Nov 23 16:43:01 2010 -0500 @@ -0,0 +1,84 @@ +/****************************************************************************** + * xc_arinc653.c + * + * XC interface to the ARINC653 scheduler + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (c) 2010 DornerWorks, Ltd. + */ + +#include "xc_private.h" + +int +xc_sched_arinc653_schedule_set( + xc_interface *xch, + struct xen_sysctl_arinc653_schedule *schedule) +{ + int rc; + DECLARE_SYSCTL; + DECLARE_HYPERCALL_BOUNCE(schedule, + sizeof(*schedule), + XC_HYPERCALL_BUFFER_BOUNCE_IN); + + if ( xc_hypercall_bounce_pre(xch, schedule) ) + return -1; + + sysctl.cmd = XEN_SYSCTL_scheduler_op; + sysctl.u.scheduler_op.cpupool_id = 0; + 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.sched_arinc653.schedule, + schedule); + + rc = do_sysctl(xch, &sysctl); + + xc_hypercall_bounce_post(xch, schedule); + + return rc; +} + +int +xc_sched_arinc653_schedule_get( + xc_interface *xch, + struct xen_sysctl_arinc653_schedule *schedule) +{ + int rc; + DECLARE_SYSCTL; + DECLARE_HYPERCALL_BOUNCE(schedule, + sizeof(*schedule), + XC_HYPERCALL_BUFFER_BOUNCE_OUT); + + if ( xc_hypercall_bounce_pre(xch, schedule) ) + return -1; + + sysctl.cmd = XEN_SYSCTL_scheduler_op; + sysctl.u.scheduler_op.cpupool_id = 0; + sysctl.u.scheduler_op.sched_id = XEN_SCHEDULER_ARINC653; + sysctl.u.scheduler_op.cmd = XEN_SYSCTL_SCHEDOP_getinfo; + set_xen_guest_handle(sysctl.u.scheduler_op.u.sched_arinc653.schedule, + schedule); + + rc = do_sysctl(xch, &sysctl); + + xc_hypercall_bounce_post(xch, schedule); + + return rc; +} + diff -r c0c1f5f0745e -r 5a4c3a1b488d tools/libxc/xenctrl.h --- a/tools/libxc/xenctrl.h Mon Nov 22 19:16:34 2010 +0000 +++ b/tools/libxc/xenctrl.h Tue Nov 23 16:43:01 2010 -0500 @@ -645,6 +645,16 @@ int xc_sched_credit2_domain_get(xc_inter uint32_t domid, struct xen_domctl_sched_credit2 *sdom); +int +xc_sched_arinc653_schedule_set( + xc_interface *xch, + struct xen_sysctl_arinc653_schedule *schedule); + +int +xc_sched_arinc653_schedule_get( + xc_interface *xch, + struct xen_sysctl_arinc653_schedule *schedule); + /** * This function sends a trigger to a domain. * diff -r c0c1f5f0745e -r 5a4c3a1b488d xen/common/Makefile --- a/xen/common/Makefile Mon Nov 22 19:16:34 2010 +0000 +++ b/xen/common/Makefile Tue Nov 23 16:43:01 2010 -0500 @@ -18,6 +18,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 -r c0c1f5f0745e -r 5a4c3a1b488d xen/common/sched_arinc653.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/common/sched_arinc653.c Tue Nov 23 16:43:01 2010 -0500 @@ -0,0 +1,770 @@ +/****************************************************************************** + * sched_arinc653.c + * + * An ARINC653-compatible scheduling algorithm for use in Xen. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (c) 2010, DornerWorks, Ltd. + */ + +/************************************************************************** + * Includes * + *************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* ARINC653_MAX_DOMAINS_PER_SCHEDULE */ + +/************************************************************************** + * 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) + +/** + * Return the global scheduler private data given the scheduler ops pointer + */ +#define SCHED_PRIV(s) ((a653sched_priv_t *)((s)->sched_data)) + +/************************************************************************** + * Private Type Definitions * + **************************************************************************/ + +/** + * 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; + +/** + * 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; + +/** + * This structure defines data that is global to an instance of the scheduler + */ +typedef struct a653sched_priv_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 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. + */ + int num_schedule_entries; + + /** + * the major frame time for the ARINC 653 schedule. + */ + s_time_t major_frame; + + /** + * the time that the next major frame starts + */ + s_time_t next_major_frame; + + /** + * pointers to all Xen VCPU structures for iterating through + */ + struct list_head vcpu_list; +} a653sched_priv_t; + +/************************************************************************** + * Helper functions * + **************************************************************************/ + +/** + * This function compares two domain handles. + * + * @param h1 Pointer to handle 1 + * @param h2 Pointer to handle 2 + * + * @return
    + *
  • <0: handle 1 is less than handle 2 + *
  • 0: handle 1 is equal to handle 2 + *
  • >0: handle 1 is greater than handle 2 + *
+ */ +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 this instance of the scheduler structure + * @param handle Pointer to handler + * @param vcpu_id VCPU ID + * + * @return
    + *
  • Pointer to the matching VCPU if one is found + *
  • NULL otherwise + *
+ */ +static struct vcpu * find_vcpu( + const struct scheduler *ops, + xen_domain_handle_t handle, + int vcpu_id) +{ + 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, &SCHED_PRIV(ops)->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 this instance of the scheduler structure + * @return + */ +static void update_schedule_vcpus(const struct scheduler *ops) +{ + /* Loop through the number of entries in the schedule */ + for (int i = 0, n_entries = SCHED_PRIV(ops)->num_schedule_entries; + i < n_entries; + i++) + { + /* Update the pointer to the Xen VCPU structure for the current entry */ + SCHED_PRIV(ops)->schedule[i].vc = + find_vcpu(ops, + SCHED_PRIV(ops)->schedule[i].dom_handle, + SCHED_PRIV(ops)->schedule[i].vcpu_id); + } +} /* end update_schedule_vcpus */ + +/** + * This function is called by the adjust_global scheduler hook to put + * in place a new ARINC653 schedule. + * + * @param ops Pointer to this instance of the scheduler structure + * + * @return
    + *
  • 0 = success + *
  • !0 = error + *
+ */ +static int +arinc653_sched_set( + const struct scheduler *ops, + struct xen_sysctl_arinc653_schedule *schedule) +{ + 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 */ + a653sched_priv_t *sched_priv = SCHED_PRIV(ops); + sched_priv->num_schedule_entries = schedule->num_sched_entries; + sched_priv->major_frame = schedule->major_frame; + for (int i = 0; i < schedule->num_sched_entries; i++) + { + memcpy(sched_priv->schedule[i].dom_handle, + schedule->sched_entries[i].dom_handle, + sizeof(sched_priv->schedule[i].dom_handle)); + sched_priv->schedule[i].vcpu_id = + schedule->sched_entries[i].vcpu_id; + sched_priv->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. + */ + sched_priv->next_major_frame = NOW(); + } + + return ret; +} /* end arinc653_sched_set */ + +/** + * This function is called by the adjust_global scheduler hook to read the + * current ARINC 653 schedule + * + * @param ops Pointer to this instance of the scheduler structure + * @return
    + *
  • 0 = success + *
  • !0 = error + *
+ */ +static int +arinc653_sched_get( + const struct scheduler *ops, + struct xen_sysctl_arinc653_schedule *schedule) +{ + a653sched_priv_t *sched_priv = SCHED_PRIV(ops); + schedule->num_sched_entries = sched_priv->num_schedule_entries; + schedule->major_frame = sched_priv->major_frame; + for (int i = 0; i < sched_priv->num_schedule_entries; i++) + { + memcpy(schedule->sched_entries[i].dom_handle, + sched_priv->schedule[i].dom_handle, + sizeof(sched_priv->schedule[i].dom_handle)); + schedule->sched_entries[i].vcpu_id = sched_priv->schedule[i].vcpu_id; + schedule->sched_entries[i].runtime = sched_priv->schedule[i].runtime; + } + return 0; +} + +/************************************************************************** + * Scheduler callback functions * + **************************************************************************/ + +/** + * This function performs initialization for an instance of the scheduler. + * + * @param ops Pointer to this instance of the scheduler structure + * + * @return
    + *
  • 0 = success + *
  • !0 = error + *
+ */ +static int +a653sched_init(struct scheduler *ops) +{ + a653sched_priv_t *prv; + + prv = xmalloc(a653sched_priv_t); + if ( prv == NULL ) + return -ENOMEM; + + memset(prv, 0, sizeof(*prv)); + ops->sched_data = prv; + + prv->schedule[0].dom_handle[0] = '\0'; + prv->schedule[0].vcpu_id = 0; + prv->schedule[0].runtime = MILLISECS(10); + prv->schedule[0].vc = NULL; + prv->num_schedule_entries = 1; + prv->major_frame = MILLISECS(10); + prv->next_major_frame = 0; + INIT_LIST_HEAD(&prv->vcpu_list); + + return 0; +} + +/** + * This function performs deinitialization for an instance of the scheduler + * + * @param ops Pointer to this instance of the scheduler structure + */ +static void +a653sched_deinit(const struct scheduler *ops) +{ + a653sched_priv_t *prv; + + prv = SCHED_PRIV(ops); + if ( prv != NULL ) + xfree(prv); +} + +/** + * This function allocates scheduler-specific data for a VCPU + * + * @param ops Pointer to this instance of the scheduler structure + * + * @return Pointer to the allocated data + */ +static void * +a653sched_alloc_vdata(const struct scheduler *ops, struct vcpu *vc, void *dd) +{ + void *ret = NULL; + + /* + * Allocate memory for the ARINC 653-specific scheduler data information + * associated with the given VCPU (vc). + */ + vc->sched_priv = xmalloc(arinc653_vcpu_t); + if (AVCPU(vc) != 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. + */ + AVCPU(vc)->vc = vc; + AVCPU(vc)->awake = 0; + if (!is_idle_vcpu(vc)) + { + list_add(&AVCPU(vc)->list, &SCHED_PRIV(ops)->vcpu_list); + } + ret = AVCPU(vc); + update_schedule_vcpus(ops); + } + + return ret; +} + +/** + * This function frees scheduler-specific VCPU data + * + * @param ops Pointer to this instance of the scheduler structure + */ +static void +a653sched_free_vdata(const struct scheduler *ops, void *priv) +{ + arinc653_vcpu_t * av = priv; + if (av != NULL) + { + /* remove the VCPU from whichever list it is on */ + list_del(&av->list); + /* free the arinc653_vcpu structure */ + xfree(av); + update_schedule_vcpus(ops); + } +} + +/** + * This function allocates scheduler-specific data for a physical CPU + * + * We do not actually make use of any per-CPU data but the hypervisor expects + * a non-NULL return value + * + * @param ops Pointer to this instance of the scheduler structure + * + * @return Pointer to the allocated data + */ +static void * +a653sched_alloc_pdata(const struct scheduler *ops, int cpu) +{ + /* return a non-NULL value to keep schedule.c happy */ + return SCHED_PRIV(ops); +} + +/** + * This function frees scheduler-specific data for a physical CPU + * + * @param ops Pointer to this instance of the scheduler structure + */ +static void +a653sched_free_pdata(const struct scheduler *ops, void *pcpu, int cpu) +{ + /* nop */ +} + +/** + * This function allocates scheduler-specific data for a domain + * + * We do not actually make use of any per-domain data but the hypervisor + * expects a non-NULL return value + * + * @param ops Pointer to this instance of the scheduler structure + * + * @return Pointer to the allocated data + */ +static void * +a653sched_alloc_domdata(const struct scheduler *ops, struct domain *dom) +{ + /* return a non-NULL value to keep schedule.c happy */ + return SCHED_PRIV(ops); +} + +/** + * This function frees scheduler-specific data for a domain + * + * @param ops Pointer to this instance of the scheduler structure + */ +static void +a653sched_free_domdata(const struct scheduler *ops, void *data) +{ + /* nop */ +} + +/** + * Xen scheduler callback function to sleep a VCPU + * + * @param ops Pointer to this instance of the scheduler structure + * @param vc Pointer to the VCPU structure for the current domain + */ +static void +a653sched_vcpu_sleep(const struct scheduler *ops, struct vcpu *vc) +{ + if (AVCPU(vc) != NULL) + { + 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); + } +} + +/** + * Xen scheduler callback function to wake up a VCPU + * + * @param ops Pointer to this instance of the scheduler structure + * @param vc Pointer to the VCPU structure for the current domain + */ +static void +a653sched_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) + { + 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; + } +} + +/** + * Xen scheduler callback function to select a VCPU to run. + * This is the main scheduler routine. + * + * @param ops Pointer to this instance of the scheduler structure + * @param now Current time + * + * @return Address of the VCPU structure scheduled to be run next + * Amount of time to execute the returned VCPU + * Flag for whether the VCPU was migrated + */ +static struct task_slice +a653sched_do_schedule( + const struct scheduler *ops, + s_time_t now, + bool_t tasklet_work_scheduled) +{ + struct task_slice ret; /* hold the chosen domain */ + struct vcpu * new_task = NULL; + static int sched_index = 0; + static s_time_t next_switch_time; + a653sched_priv_t *sched_priv = SCHED_PRIV(ops); + + if (now >= sched_priv->next_major_frame) + { + /* time to enter a new major frame + * the first time this function is called, this will be true */ + /* start with the first domain in the schedule */ + sched_index = 0; + sched_priv->next_major_frame = now + sched_priv->major_frame; + next_switch_time = now + sched_priv->schedule[0].runtime; + } + else + { + while (now >= next_switch_time + && sched_index < sched_priv->num_schedule_entries) + { + /* time to switch to the next domain in this major frame */ + sched_index++; + next_switch_time += sched_priv->schedule[sched_index].runtime; + } + } + + /* + * If we exhausted the domains in the schedule and still have time left + * in the major frame then switch next at the next major frame + */ + if (sched_index >= sched_priv->num_schedule_entries) + { + next_switch_time = sched_priv->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 < sched_priv->num_schedule_entries) + ? sched_priv->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) != 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(now >= sched_priv->next_major_frame); + + /* Tasklet work (which runs in idle VCPU context) overrides all else. */ + if ( tasklet_work_scheduled ) + { + new_task = IDLETASK(0); + } + + /* + * 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 - now; + ret.task = new_task; + ret.migrated = 0; /* we do not support migration */ + + BUG_ON(ret.time <= 0); + + return ret; +} + +/** + * Xen scheduler callback function to select a CPU for the VCPU to run on + * + * @param ops Pointer to this instance of the scheduler structure + * @param v Pointer to the VCPU structure for the current domain + * + * @return Number of selected physical CPU + */ +static int +a653sched_pick_cpu(const struct scheduler *ops, struct vcpu *vc) +{ + /* this implementation only supports one physical CPU */ + return 0; +} + +/** + * Xen scheduler callback function to perform a global (not domain-specific) + * adjustment. It is used by the ARINC 653 scheduler to put in place a new + * ARINC 653 schedule or to retrieve the schedule currently in place. + * + * @param ops Pointer to this instance of the scheduler structure + * @param sc Pointer to the scheduler operation specified by Domain 0 + */ +static int +a653sched_adjust_global(const struct scheduler *ops, + struct xen_sysctl_scheduler_op *sc) +{ + xen_sysctl_arinc653_schedule_t local_sched; + int rc = -EINVAL; + switch (sc->cmd) + { + case XEN_SYSCTL_SCHEDOP_putinfo: + copy_from_guest(&local_sched, sc->u.sched_arinc653.schedule, 1); + rc = arinc653_sched_set(ops, &local_sched); + break; + case XEN_SYSCTL_SCHEDOP_getinfo: + rc = arinc653_sched_get(ops, &local_sched); + copy_to_guest(sc->u.sched_arinc653.schedule, &local_sched, 1); + break; + } + return rc; +} + +/** + * 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 = NULL, + + .init = a653sched_init, + .deinit = a653sched_deinit, + + .free_vdata = a653sched_free_vdata, + .alloc_vdata = a653sched_alloc_vdata, + + .free_pdata = a653sched_free_pdata, + .alloc_pdata = a653sched_alloc_pdata, + + .free_domdata = a653sched_free_domdata, + .alloc_domdata = a653sched_alloc_domdata, + + .init_domain = NULL, + .destroy_domain = NULL, + + .insert_vcpu = NULL, + .remove_vcpu = NULL, + + .sleep = a653sched_vcpu_sleep, + .wake = a653sched_vcpu_wake, + .yield = NULL, + .context_saved = NULL, + + .do_schedule = a653sched_do_schedule, + + .pick_cpu = a653sched_pick_cpu, + + .adjust = NULL, + .adjust_global = a653sched_adjust_global, + + .dump_settings = NULL, + .dump_cpu_state = NULL, + + .tick_suspend = NULL, + .tick_resume = NULL, +}; diff -r c0c1f5f0745e -r 5a4c3a1b488d xen/common/schedule.c --- a/xen/common/schedule.c Mon Nov 22 19:16:34 2010 +0000 +++ b/xen/common/schedule.c Tue Nov 23 16:43:01 2010 -0500 @@ -60,10 +60,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 -r c0c1f5f0745e -r 5a4c3a1b488d xen/include/public/domctl.h --- a/xen/include/public/domctl.h Mon Nov 22 19:16:34 2010 +0000 +++ b/xen/include/public/domctl.h Tue Nov 23 16:43:01 2010 -0500 @@ -23,6 +23,8 @@ * * Copyright (c) 2002-2003, B Dragovic * Copyright (c) 2002-2006, K Fraser + * + * ARINC653 Scheduler type added by DornerWorks . */ #ifndef __XEN_PUBLIC_DOMCTL_H__ @@ -300,6 +302,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 -r c0c1f5f0745e -r 5a4c3a1b488d xen/include/public/sysctl.h --- a/xen/include/public/sysctl.h Mon Nov 22 19:16:34 2010 +0000 +++ b/xen/include/public/sysctl.h Tue Nov 23 16:43:01 2010 -0500 @@ -33,6 +33,7 @@ #include "xen.h" #include "domctl.h" +#include "sysctl_arinc653.h" #define XEN_SYSCTL_INTERFACE_VERSION 0x00000008 @@ -551,6 +552,9 @@ 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_arinc653_schedule_t) schedule; + } sched_arinc653; } u; }; typedef struct xen_sysctl_scheduler_op xen_sysctl_scheduler_op_t; diff -r c0c1f5f0745e -r 5a4c3a1b488d xen/include/public/sysctl_arinc653.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/public/sysctl_arinc653.h Tue Nov 23 16:43:01 2010 -0500 @@ -0,0 +1,61 @@ +/****************************************************************************** + * sysctl_arinc653.h + * + * System management operations for arinc653 scheduler + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (c) 2010 DornerWorks, Ltd. + */ + +#ifndef __XEN_PUBLIC_SYSCTL_ARINC653_H__ +#define __XEN_PUBLIC_SYSCTL_ARINC653_H__ + +#include "xen.h" + +#define ARINC653_MAX_DOMAINS_PER_SCHEDULE 64 +/* + * This structure is used to pass a new ARINC653 schedule from a + * privileged domain (ie dom0) to Xen. + */ +struct xen_sysctl_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_arinc653_schedule xen_sysctl_arinc653_schedule_t; +DEFINE_XEN_GUEST_HANDLE(xen_sysctl_arinc653_schedule_t); + +#endif /* __XEN_PUBLIC_SYSCTL_ARINC653_H__ */ +