1 /******************************************************************************
2  * sched_arinc653.c
3  *
4  * An ARINC653-compatible scheduling algorithm for use in Xen.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Copyright (c) 2010, DornerWorks, Ltd. <DornerWorks.com>
25  */
26 
27 #include <xen/lib.h>
28 #include <xen/sched.h>
29 #include <xen/timer.h>
30 #include <xen/softirq.h>
31 #include <xen/time.h>
32 #include <xen/errno.h>
33 #include <xen/list.h>
34 #include <xen/guest_access.h>
35 #include <public/sysctl.h>
36 
37 #include "private.h"
38 
39 /**************************************************************************
40  * Private Macros                                                         *
41  **************************************************************************/
42 
43 /**
44  * Default timeslice for domain 0.
45  */
46 #define DEFAULT_TIMESLICE MILLISECS(10)
47 
48 /**
49  * Retrieve the idle UNIT for a given physical CPU
50  */
51 #define IDLETASK(cpu)  (sched_idle_unit(cpu))
52 
53 /**
54  * Return a pointer to the ARINC 653-specific scheduler data information
55  * associated with the given UNIT (unit)
56  */
57 #define AUNIT(unit) ((arinc653_unit_t *)(unit)->priv)
58 
59 /**
60  * Return the global scheduler private data given the scheduler ops pointer
61  */
62 #define SCHED_PRIV(s) ((a653sched_priv_t *)((s)->sched_data))
63 
64 /**************************************************************************
65  * Private Type Definitions                                               *
66  **************************************************************************/
67 
68 /**
69  * The arinc653_unit_t structure holds ARINC 653-scheduler-specific
70  * information for all non-idle UNITs
71  */
72 typedef struct arinc653_unit_s
73 {
74     /* unit points to Xen's struct sched_unit so we can get to it from an
75      * arinc653_unit_t pointer. */
76     struct sched_unit * unit;
77     /* awake holds whether the UNIT has been woken with vcpu_wake() */
78     bool                awake;
79     /* list holds the linked list information for the list this UNIT
80      * is stored in */
81     struct list_head    list;
82 } arinc653_unit_t;
83 
84 /**
85  * The sched_entry_t structure holds a single entry of the
86  * ARINC 653 schedule.
87  */
88 typedef struct sched_entry_s
89 {
90     /* dom_handle holds the handle ("UUID") for the domain that this
91      * schedule entry refers to. */
92     xen_domain_handle_t dom_handle;
93     /* unit_id holds the UNIT number for the UNIT that this schedule
94      * entry refers to. */
95     int                 unit_id;
96     /* runtime holds the number of nanoseconds that the UNIT for this
97      * schedule entry should be allowed to run per major frame. */
98     s_time_t            runtime;
99     /* unit holds a pointer to the Xen sched_unit structure */
100     struct sched_unit * unit;
101 } sched_entry_t;
102 
103 /**
104  * This structure defines data that is global to an instance of the scheduler
105  */
106 typedef struct a653sched_priv_s
107 {
108     /* lock for the whole pluggable scheduler, nests inside cpupool_lock */
109     spinlock_t lock;
110 
111     /**
112      * This array holds the active ARINC 653 schedule.
113      *
114      * When the system tries to start a new UNIT, this schedule is scanned
115      * to look for a matching (handle, UNIT #) pair. If both the handle (UUID)
116      * and UNIT number match, then the UNIT is allowed to run. Its run time
117      * (per major frame) is given in the third entry of the schedule.
118      */
119     sched_entry_t schedule[ARINC653_MAX_DOMAINS_PER_SCHEDULE];
120 
121     /**
122      * This variable holds the number of entries that are valid in
123      * the arinc653_schedule table.
124      *
125      * This is not necessarily the same as the number of domains in the
126      * schedule. A domain could be listed multiple times within the schedule,
127      * or a domain with multiple UNITs could have a different
128      * schedule entry for each UNIT.
129      */
130     unsigned int num_schedule_entries;
131 
132     /**
133      * the major frame time for the ARINC 653 schedule.
134      */
135     s_time_t major_frame;
136 
137     /**
138      * the time that the next major frame starts
139      */
140     s_time_t next_major_frame;
141 
142     /**
143      * pointers to all Xen UNIT structures for iterating through
144      */
145     struct list_head unit_list;
146 } a653sched_priv_t;
147 
148 /**************************************************************************
149  * Helper functions                                                       *
150  **************************************************************************/
151 
152 /**
153  * This function compares two domain handles.
154  *
155  * @param h1        Pointer to handle 1
156  * @param h2        Pointer to handle 2
157  *
158  * @return          <ul>
159  *                  <li> <0:  handle 1 is less than handle 2
160  *                  <li>  0:  handle 1 is equal to handle 2
161  *                  <li> >0:  handle 1 is greater than handle 2
162  *                  </ul>
163  */
dom_handle_cmp(const xen_domain_handle_t h1,const xen_domain_handle_t h2)164 static int dom_handle_cmp(const xen_domain_handle_t h1,
165                           const xen_domain_handle_t h2)
166 {
167     return memcmp(h1, h2, sizeof(xen_domain_handle_t));
168 }
169 
170 /**
171  * This function searches the unit list to find a UNIT that matches
172  * the domain handle and UNIT ID specified.
173  *
174  * @param ops       Pointer to this instance of the scheduler structure
175  * @param handle    Pointer to handler
176  * @param unit_id   UNIT ID
177  *
178  * @return          <ul>
179  *                  <li> Pointer to the matching UNIT if one is found
180  *                  <li> NULL otherwise
181  *                  </ul>
182  */
find_unit(const struct scheduler * ops,xen_domain_handle_t handle,int unit_id)183 static struct sched_unit *find_unit(
184     const struct scheduler *ops,
185     xen_domain_handle_t handle,
186     int unit_id)
187 {
188     arinc653_unit_t *aunit;
189 
190     /* loop through the unit_list looking for the specified UNIT */
191     list_for_each_entry ( aunit, &SCHED_PRIV(ops)->unit_list, list )
192         if ( (dom_handle_cmp(aunit->unit->domain->handle, handle) == 0)
193              && (unit_id == aunit->unit->unit_id) )
194             return aunit->unit;
195 
196     return NULL;
197 }
198 
199 /**
200  * This function updates the pointer to the Xen UNIT structure for each entry
201  * in the ARINC 653 schedule.
202  *
203  * @param ops       Pointer to this instance of the scheduler structure
204  * @return          <None>
205  */
update_schedule_units(const struct scheduler * ops)206 static void update_schedule_units(const struct scheduler *ops)
207 {
208     unsigned int i, n_entries = SCHED_PRIV(ops)->num_schedule_entries;
209 
210     for ( i = 0; i < n_entries; i++ )
211         SCHED_PRIV(ops)->schedule[i].unit =
212             find_unit(ops,
213                       SCHED_PRIV(ops)->schedule[i].dom_handle,
214                       SCHED_PRIV(ops)->schedule[i].unit_id);
215 }
216 
217 /**
218  * This function is called by the adjust_global scheduler hook to put
219  * in place a new ARINC653 schedule.
220  *
221  * @param ops       Pointer to this instance of the scheduler structure
222  *
223  * @return          <ul>
224  *                  <li> 0 = success
225  *                  <li> !0 = error
226  *                  </ul>
227  */
228 static int
arinc653_sched_set(const struct scheduler * ops,struct xen_sysctl_arinc653_schedule * schedule)229 arinc653_sched_set(
230     const struct scheduler *ops,
231     struct xen_sysctl_arinc653_schedule *schedule)
232 {
233     a653sched_priv_t *sched_priv = SCHED_PRIV(ops);
234     s_time_t total_runtime = 0;
235     unsigned int i;
236     unsigned long flags;
237     int rc = -EINVAL;
238 
239     spin_lock_irqsave(&sched_priv->lock, flags);
240 
241     /* Check for valid major frame and number of schedule entries. */
242     if ( (schedule->major_frame <= 0)
243          || (schedule->num_sched_entries < 1)
244          || (schedule->num_sched_entries > ARINC653_MAX_DOMAINS_PER_SCHEDULE) )
245         goto fail;
246 
247     for ( i = 0; i < schedule->num_sched_entries; i++ )
248     {
249         /* Check for a valid run time. */
250         if ( schedule->sched_entries[i].runtime <= 0 )
251             goto fail;
252 
253         /* Add this entry's run time to total run time. */
254         total_runtime += schedule->sched_entries[i].runtime;
255     }
256 
257     /*
258      * Error if the major frame is not large enough to run all entries as
259      * indicated by comparing the total run time to the major frame length.
260      */
261     if ( total_runtime > schedule->major_frame )
262         goto fail;
263 
264     /* Copy the new schedule into place. */
265     sched_priv->num_schedule_entries = schedule->num_sched_entries;
266     sched_priv->major_frame = schedule->major_frame;
267     for ( i = 0; i < schedule->num_sched_entries; i++ )
268     {
269         memcpy(sched_priv->schedule[i].dom_handle,
270                schedule->sched_entries[i].dom_handle,
271                sizeof(sched_priv->schedule[i].dom_handle));
272         sched_priv->schedule[i].unit_id =
273             schedule->sched_entries[i].vcpu_id;
274         sched_priv->schedule[i].runtime =
275             schedule->sched_entries[i].runtime;
276     }
277     update_schedule_units(ops);
278 
279     /*
280      * The newly-installed schedule takes effect immediately. We do not even
281      * wait for the current major frame to expire.
282      *
283      * Signal a new major frame to begin. The next major frame is set up by
284      * the do_schedule callback function when it is next invoked.
285      */
286     sched_priv->next_major_frame = NOW();
287 
288     rc = 0;
289 
290  fail:
291     spin_unlock_irqrestore(&sched_priv->lock, flags);
292     return rc;
293 }
294 
295 /**
296  * This function is called by the adjust_global scheduler hook to read the
297  * current ARINC 653 schedule
298  *
299  * @param ops       Pointer to this instance of the scheduler structure
300  * @return          <ul>
301  *                  <li> 0 = success
302  *                  <li> !0 = error
303  *                  </ul>
304  */
305 static int
arinc653_sched_get(const struct scheduler * ops,struct xen_sysctl_arinc653_schedule * schedule)306 arinc653_sched_get(
307     const struct scheduler *ops,
308     struct xen_sysctl_arinc653_schedule *schedule)
309 {
310     a653sched_priv_t *sched_priv = SCHED_PRIV(ops);
311     unsigned int i;
312     unsigned long flags;
313 
314     spin_lock_irqsave(&sched_priv->lock, flags);
315 
316     schedule->num_sched_entries = sched_priv->num_schedule_entries;
317     schedule->major_frame = sched_priv->major_frame;
318     for ( i = 0; i < sched_priv->num_schedule_entries; i++ )
319     {
320         memcpy(schedule->sched_entries[i].dom_handle,
321                sched_priv->schedule[i].dom_handle,
322                sizeof(sched_priv->schedule[i].dom_handle));
323         schedule->sched_entries[i].vcpu_id = sched_priv->schedule[i].unit_id;
324         schedule->sched_entries[i].runtime = sched_priv->schedule[i].runtime;
325     }
326 
327     spin_unlock_irqrestore(&sched_priv->lock, flags);
328 
329     return 0;
330 }
331 
332 /**************************************************************************
333  * Scheduler callback functions                                           *
334  **************************************************************************/
335 
336 /**
337  * This function performs initialization for an instance of the scheduler.
338  *
339  * @param ops       Pointer to this instance of the scheduler structure
340  *
341  * @return          <ul>
342  *                  <li> 0 = success
343  *                  <li> !0 = error
344  *                  </ul>
345  */
346 static int
a653sched_init(struct scheduler * ops)347 a653sched_init(struct scheduler *ops)
348 {
349     a653sched_priv_t *prv;
350 
351     prv = xzalloc(a653sched_priv_t);
352     if ( prv == NULL )
353         return -ENOMEM;
354 
355     ops->sched_data = prv;
356 
357     prv->next_major_frame = 0;
358     spin_lock_init(&prv->lock);
359     INIT_LIST_HEAD(&prv->unit_list);
360 
361     return 0;
362 }
363 
364 /**
365  * This function performs deinitialization for an instance of the scheduler
366  *
367  * @param ops       Pointer to this instance of the scheduler structure
368  */
369 static void
a653sched_deinit(struct scheduler * ops)370 a653sched_deinit(struct scheduler *ops)
371 {
372     xfree(SCHED_PRIV(ops));
373     ops->sched_data = NULL;
374 }
375 
376 /**
377  * This function allocates scheduler-specific data for a UNIT
378  *
379  * @param ops       Pointer to this instance of the scheduler structure
380  * @param unit      Pointer to struct sched_unit
381  *
382  * @return          Pointer to the allocated data
383  */
384 static void *
a653sched_alloc_udata(const struct scheduler * ops,struct sched_unit * unit,void * dd)385 a653sched_alloc_udata(const struct scheduler *ops, struct sched_unit *unit,
386                       void *dd)
387 {
388     a653sched_priv_t *sched_priv = SCHED_PRIV(ops);
389     arinc653_unit_t *svc;
390     unsigned int entry;
391     unsigned long flags;
392 
393     /*
394      * Allocate memory for the ARINC 653-specific scheduler data information
395      * associated with the given UNIT (unit).
396      */
397     svc = xmalloc(arinc653_unit_t);
398     if ( svc == NULL )
399         return NULL;
400 
401     spin_lock_irqsave(&sched_priv->lock, flags);
402 
403     /*
404      * Add every one of dom0's units to the schedule, as long as there are
405      * slots available.
406      */
407     if ( unit->domain->domain_id == 0 )
408     {
409         entry = sched_priv->num_schedule_entries;
410 
411         if ( entry < ARINC653_MAX_DOMAINS_PER_SCHEDULE )
412         {
413             sched_priv->schedule[entry].dom_handle[0] = '\0';
414             sched_priv->schedule[entry].unit_id = unit->unit_id;
415             sched_priv->schedule[entry].runtime = DEFAULT_TIMESLICE;
416             sched_priv->schedule[entry].unit = unit;
417 
418             sched_priv->major_frame += DEFAULT_TIMESLICE;
419             ++sched_priv->num_schedule_entries;
420         }
421     }
422 
423     /*
424      * Initialize our ARINC 653 scheduler-specific information for the UNIT.
425      * The UNIT starts "asleep." When Xen is ready for the UNIT to run, it
426      * will call the vcpu_wake scheduler callback function and our scheduler
427      * will mark the UNIT awake.
428      */
429     svc->unit = unit;
430     svc->awake = false;
431     if ( !is_idle_unit(unit) )
432         list_add(&svc->list, &SCHED_PRIV(ops)->unit_list);
433     update_schedule_units(ops);
434 
435     spin_unlock_irqrestore(&sched_priv->lock, flags);
436 
437     return svc;
438 }
439 
440 /**
441  * This function frees scheduler-specific UNIT data
442  *
443  * @param ops       Pointer to this instance of the scheduler structure
444  */
445 static void
a653sched_free_udata(const struct scheduler * ops,void * priv)446 a653sched_free_udata(const struct scheduler *ops, void *priv)
447 {
448     a653sched_priv_t *sched_priv = SCHED_PRIV(ops);
449     arinc653_unit_t *av = priv;
450     unsigned long flags;
451 
452     if (av == NULL)
453         return;
454 
455     spin_lock_irqsave(&sched_priv->lock, flags);
456 
457     if ( !is_idle_unit(av->unit) )
458         list_del(&av->list);
459 
460     xfree(av);
461     update_schedule_units(ops);
462 
463     spin_unlock_irqrestore(&sched_priv->lock, flags);
464 }
465 
466 /**
467  * Xen scheduler callback function to sleep a UNIT
468  *
469  * @param ops       Pointer to this instance of the scheduler structure
470  * @param unit      Pointer to struct sched_unit
471  */
472 static void
a653sched_unit_sleep(const struct scheduler * ops,struct sched_unit * unit)473 a653sched_unit_sleep(const struct scheduler *ops, struct sched_unit *unit)
474 {
475     if ( AUNIT(unit) != NULL )
476         AUNIT(unit)->awake = false;
477 
478     /*
479      * If the UNIT being put to sleep is the same one that is currently
480      * running, raise a softirq to invoke the scheduler to switch domains.
481      */
482     if ( get_sched_res(sched_unit_master(unit))->curr == unit )
483         cpu_raise_softirq(sched_unit_master(unit), SCHEDULE_SOFTIRQ);
484 }
485 
486 /**
487  * Xen scheduler callback function to wake up a UNIT
488  *
489  * @param ops       Pointer to this instance of the scheduler structure
490  * @param unit      Pointer to struct sched_unit
491  */
492 static void
a653sched_unit_wake(const struct scheduler * ops,struct sched_unit * unit)493 a653sched_unit_wake(const struct scheduler *ops, struct sched_unit *unit)
494 {
495     if ( AUNIT(unit) != NULL )
496         AUNIT(unit)->awake = true;
497 
498     cpu_raise_softirq(sched_unit_master(unit), SCHEDULE_SOFTIRQ);
499 }
500 
501 /**
502  * Xen scheduler callback function to select a UNIT to run.
503  * This is the main scheduler routine.
504  *
505  * @param ops       Pointer to this instance of the scheduler structure
506  * @param now       Current time
507  */
508 static void
a653sched_do_schedule(const struct scheduler * ops,struct sched_unit * prev,s_time_t now,bool tasklet_work_scheduled)509 a653sched_do_schedule(
510     const struct scheduler *ops,
511     struct sched_unit *prev,
512     s_time_t now,
513     bool tasklet_work_scheduled)
514 {
515     struct sched_unit *new_task = NULL;
516     static unsigned int sched_index = 0;
517     static s_time_t next_switch_time;
518     a653sched_priv_t *sched_priv = SCHED_PRIV(ops);
519     const unsigned int cpu = sched_get_resource_cpu(smp_processor_id());
520     unsigned long flags;
521 
522     spin_lock_irqsave(&sched_priv->lock, flags);
523 
524     if ( sched_priv->num_schedule_entries < 1 )
525         sched_priv->next_major_frame = now + DEFAULT_TIMESLICE;
526     else if ( now >= sched_priv->next_major_frame )
527     {
528         /* time to enter a new major frame
529          * the first time this function is called, this will be true */
530         /* start with the first domain in the schedule */
531         sched_index = 0;
532         sched_priv->next_major_frame = now + sched_priv->major_frame;
533         next_switch_time = now + sched_priv->schedule[0].runtime;
534     }
535     else
536     {
537         while ( (now >= next_switch_time)
538                 && (sched_index < sched_priv->num_schedule_entries) )
539         {
540             /* time to switch to the next domain in this major frame */
541             sched_index++;
542             next_switch_time += sched_priv->schedule[sched_index].runtime;
543         }
544     }
545 
546     /*
547      * If we exhausted the domains in the schedule and still have time left
548      * in the major frame then switch next at the next major frame.
549      */
550     if ( sched_index >= sched_priv->num_schedule_entries )
551         next_switch_time = sched_priv->next_major_frame;
552 
553     /*
554      * If there are more domains to run in the current major frame, set
555      * new_task equal to the address of next domain's sched_unit structure.
556      * Otherwise, set new_task equal to the address of the idle task's
557      * sched_unit structure.
558      */
559     new_task = (sched_index < sched_priv->num_schedule_entries)
560         ? sched_priv->schedule[sched_index].unit
561         : IDLETASK(cpu);
562 
563     /* Check to see if the new task can be run (awake & runnable). */
564     if ( !((new_task != NULL)
565            && (AUNIT(new_task) != NULL)
566            && AUNIT(new_task)->awake
567            && unit_runnable_state(new_task)) )
568         new_task = IDLETASK(cpu);
569     BUG_ON(new_task == NULL);
570 
571     /*
572      * Check to make sure we did not miss a major frame.
573      * This is a good test for robust partitioning.
574      */
575     BUG_ON(now >= sched_priv->next_major_frame);
576 
577     spin_unlock_irqrestore(&sched_priv->lock, flags);
578 
579     /* Tasklet work (which runs in idle UNIT context) overrides all else. */
580     if ( tasklet_work_scheduled )
581         new_task = IDLETASK(cpu);
582 
583     /* Running this task would result in a migration */
584     if ( !is_idle_unit(new_task)
585          && (sched_unit_master(new_task) != cpu) )
586         new_task = IDLETASK(cpu);
587 
588     /*
589      * Return the amount of time the next domain has to run and the address
590      * of the selected task's UNIT structure.
591      */
592     prev->next_time = next_switch_time - now;
593     prev->next_task = new_task;
594     new_task->migrated = false;
595 
596     BUG_ON(prev->next_time <= 0);
597 }
598 
599 /**
600  * Xen scheduler callback function to select a resource for the UNIT to run on
601  *
602  * @param ops       Pointer to this instance of the scheduler structure
603  * @param unit      Pointer to struct sched_unit
604  *
605  * @return          Scheduler resource to run on
606  */
607 static struct sched_resource *
a653sched_pick_resource(const struct scheduler * ops,const struct sched_unit * unit)608 a653sched_pick_resource(const struct scheduler *ops,
609                         const struct sched_unit *unit)
610 {
611     const cpumask_t *online;
612     unsigned int cpu;
613 
614     /*
615      * If present, prefer unit's current processor, else
616      * just find the first valid unit.
617      */
618     online = cpupool_domain_master_cpumask(unit->domain);
619 
620     cpu = cpumask_first(online);
621 
622     if ( cpumask_test_cpu(sched_unit_master(unit), online)
623          || (cpu >= nr_cpu_ids) )
624         cpu = sched_unit_master(unit);
625 
626     return get_sched_res(cpu);
627 }
628 
629 /**
630  * Xen scheduler callback to change the scheduler of a cpu
631  *
632  * @param new_ops   Pointer to this instance of the scheduler structure
633  * @param cpu       The cpu that is changing scheduler
634  * @param pdata     scheduler specific PCPU data (we don't have any)
635  * @param vdata     scheduler specific UNIT data of the idle unit
636  */
637 static spinlock_t *
a653_switch_sched(struct scheduler * new_ops,unsigned int cpu,void * pdata,void * vdata)638 a653_switch_sched(struct scheduler *new_ops, unsigned int cpu,
639                   void *pdata, void *vdata)
640 {
641     struct sched_resource *sr = get_sched_res(cpu);
642     const arinc653_unit_t *svc = vdata;
643 
644     ASSERT(!pdata && svc && is_idle_unit(svc->unit));
645 
646     sched_idle_unit(cpu)->priv = vdata;
647 
648     return &sr->_lock;
649 }
650 
651 /**
652  * Xen scheduler callback function to perform a global (not domain-specific)
653  * adjustment. It is used by the ARINC 653 scheduler to put in place a new
654  * ARINC 653 schedule or to retrieve the schedule currently in place.
655  *
656  * @param ops       Pointer to this instance of the scheduler structure
657  * @param sc        Pointer to the scheduler operation specified by Domain 0
658  */
659 static int
a653sched_adjust_global(const struct scheduler * ops,struct xen_sysctl_scheduler_op * sc)660 a653sched_adjust_global(const struct scheduler *ops,
661                         struct xen_sysctl_scheduler_op *sc)
662 {
663     struct xen_sysctl_arinc653_schedule local_sched;
664     int rc = -EINVAL;
665 
666     switch ( sc->cmd )
667     {
668     case XEN_SYSCTL_SCHEDOP_putinfo:
669         if ( copy_from_guest(&local_sched, sc->u.sched_arinc653.schedule, 1) )
670         {
671             rc = -EFAULT;
672             break;
673         }
674 
675         rc = arinc653_sched_set(ops, &local_sched);
676         break;
677     case XEN_SYSCTL_SCHEDOP_getinfo:
678         memset(&local_sched, -1, sizeof(local_sched));
679         rc = arinc653_sched_get(ops, &local_sched);
680         if ( rc )
681             break;
682 
683         if ( copy_to_guest(sc->u.sched_arinc653.schedule, &local_sched, 1) )
684             rc = -EFAULT;
685         break;
686     }
687 
688     return rc;
689 }
690 
691 /**
692  * This structure defines our scheduler for Xen.
693  * The entries tell Xen where to find our scheduler-specific
694  * callback functions.
695  * The symbol must be visible to the rest of Xen at link time.
696  */
697 static const struct scheduler sched_arinc653_def = {
698     .name           = "ARINC 653 Scheduler",
699     .opt_name       = "arinc653",
700     .sched_id       = XEN_SCHEDULER_ARINC653,
701     .sched_data     = NULL,
702 
703     .init           = a653sched_init,
704     .deinit         = a653sched_deinit,
705 
706     .free_udata     = a653sched_free_udata,
707     .alloc_udata    = a653sched_alloc_udata,
708 
709     .insert_unit    = NULL,
710     .remove_unit    = NULL,
711 
712     .sleep          = a653sched_unit_sleep,
713     .wake           = a653sched_unit_wake,
714     .yield          = NULL,
715     .context_saved  = NULL,
716 
717     .do_schedule    = a653sched_do_schedule,
718 
719     .pick_resource  = a653sched_pick_resource,
720 
721     .switch_sched   = a653_switch_sched,
722 
723     .adjust         = NULL,
724     .adjust_global  = a653sched_adjust_global,
725 
726     .dump_settings  = NULL,
727     .dump_cpu_state = NULL,
728 };
729 
730 REGISTER_SCHEDULER(sched_arinc653_def);
731 
732 /*
733  * Local variables:
734  * mode: C
735  * c-file-style: "BSD"
736  * c-basic-offset: 4
737  * tab-width: 4
738  * indent-tabs-mode: nil
739  * End:
740  */
741