GSoC 2013 - RTEMS Virtualization Layer Project

Progress, Issues, Design

How Late Is It?

The big question is: How can we pass the time to RTEMS? POK doesn’t provide a mechanism to pass time to a partition, however, the partition can ask how late it is. But this doesn’t help. Hence, we need to design a new mechanism in POK and RTEMS to let the two work together.

Caution: This is a very long post!

What we need …

.. in POK

  • Forward interrupts to registered partitions
  • Register several partitions to the same interrupt, aka interrupt chaining
  • Keep a count for every partition’s pending interrupt
  • Checkpointing the time in the scheduler at partition entry and exit

.. in RTEMS

  • A time warp function to cover the time, when the partition was not scheduled

Current interrupt control in POK (x86)

Registering a handler

This an excerpt from several files: pit.c, time.h

1
2
3
4
5
6
7
8
9
10
#define CLOCK_HANDLER pok_tick_counter +=1; pok_sched();

INTERRUPT_HANDLER (pit_interrupt)
{
  (void) frame;
  pok_pic_eoi(PIT_IRQ)
  CLOCK_HANDLER
}

pok_bsp_irq_register (PIT_IRQ, pit_interrupt);

The function pok_bsp_irq_register is defined in bsp.c:

1
2
3
4
5
6
7
8
pok_ret_t pob_bsp_irq_register( uint8_t irq, void (*handler)(void))
{
  pok_pic_unmask (irq);

  pok_arch_event_register (32 + irq, handler);

  return (POK_ERRNO_OK);
}

And in turn pok_arch_event_register is defined in arch.c:

1
2
3
4
5
6
7
pok_ret_t pok_arch_event_register (uint8_t vector, void (*handler)(void))
{
  pok_idt_set_gate ( vector, GDT_CORE_CODE_SEGMENT << 3, (uint32_t)handler,
            IDTE_TRAP, 3);

  return (POK_ERROR_OK);
}

This last function is defined in event.c and is setting up an idt_entry_t.

This shows two things: First, the number of the occurring interrupt isn’t passed on to the handler. Second, one vector refers to one entry in the idt table and therefore one interrupt can only invoke one handler.

Interrupt chaining && counting pending ones

  • Handler list

Instead of one handler, keep a list of handler functions registered to that specific interrupt. But the handler is converted into an so called offset_low and offset_high. Therefore, I don’t think this is a good solution.

  • Meta handler

Define a meta handler object, which registers a requested interrupt and keeps track of every registered handler. Additionally, it could keep a count of pending interrupts to each partition.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
struct meta_handler
{
  (void) (*handler_list)(void)  reg_handler[POK_CONFIG_NB_PARTITIONS];
  unsigned int            pending[POK_CONFIG_NB_PARTITIONS];
  unsigned int            vector;

  void receive_irq( void )
  {
    for( i = 0; i < POK_CONFIG_NB_PARTITIONS]; i++)
      if( i != POK_SHED_CURRENT_PARTITION && reg_handler[i] != NULL )
        pending[i]++;

    if( reg_handler[POK_SHED_CURRENT_PARTITION] != NULL )
      meta_deliver_irq();
  }

  void meta_deliver_irq( void )
  {
    reg_handler[POK_SCHED_CURRENT_PARTITION]();
  }

  void register_meta_handler( uint16_t vec, void (*handler)(void) )
  {
    vector = vec;
    reg_handler[POK_SHED_CURRENT_PARTITION] = handler;
    pending[POK_SHED_CURRENT_PARTITION] = 0;

    pok_idt_set_gate( vector, GDT_CORE_CODE_SEGMENT << 3,
  (uint32_t) this.receive_irq(), IDTE_TRAP, 3);
  }

}
  • Why don’t I use a dynamically growing linked list? The execution time is equal every time it is run. This eases estimations.

  • Why do I use the POK_SHED_CURRENT_PARTITION as an index into the arrays? Both arrays will be in sync all the time, as they don’t grow and shrink dynamically.

  • Improvements? I could define an array containing the registered partition indexes and a counter counting the number of registered partitions. This would prevent me to run over all POK_CONFIG_NB_PARTITIONS in the for-loop.

Forwarding Interrupts

The proposed meta_handler doesn’t solve the problem of just forwarding the interrupts. I still need to register a handler for every interrupt and it is still missing the ability to pass along the vector number.

Either I build custom handler, containing the IRQ number for each IRQ or I change the POK handler model to accept one variable. As the meta handler is capable of adding the vector number on the fly, the latter is possible. However, the interrupt handler are generated by assembly code, which I need to understand first.

Scheduler Time Checkpoints

The POK scheduler needs to keep track of each partition entry and exit, so it can tell the partition how many clock ticks it missed. I haven’t come around to take a look at the scheduler implementation and how this can be inserted, but on the other hand I think, that pending clock interrupts will pretty much have the same effect. They accumulate during the time the partition is off-line and are delivered, when it comes on-line again. This part needs discussion.

RTEMS Time Warp

Due to the round robin scheduling, the RTEMS guest will run until it has consumed it’s time slice and then wait for the rest of the major frame to pass. This leads to a drift between RTEMS execution time and wall-clock time, which is unacceptable for a real-time system.

To reduce the drift, RTEMS will time warp every time it is scheduled. The time warp will apply all ticks to the RTEMS internal counters. This can either be done via a checkpoint extension in the scheduler or via pending clock interrupts. As mentioned above this needs to be discussed.

During this time warp deadlines might be missed, but this is more a matter of system design, than of wrong behavior on the time side.