Fundamentals 20 min read

Injecting Timer Interrupts to Simulate Scheduler Events in a Linux VMM

This article explains how to use high‑resolution timers to inject clock interrupts and force a pre‑emptive schedule inside a QEMU/KVM virtual machine monitor, detailing the design, register saving/restoring, code implementation, and hardware constraints for reliable testing of kernel paths.

Alibaba Cloud Developer
Alibaba Cloud Developer
Alibaba Cloud Developer
Injecting Timer Interrupts to Simulate Scheduler Events in a Linux VMM

1. Requirement Background

Virtualization is a core cloud technology; a hypervisor (VMM) such as QEMU/KVM separates physical resources (CPU, memory) into isolated virtual machines. To test VMM behavior under realistic conditions, it is necessary to simulate timer interrupts and scheduling events that cause a guest to exit to the host, save and restore registers, and optionally trigger a pre‑emptive schedule.

2. Design

2.1 Process Flow

Insert a kernel module that registers a timer interrupt firing every 20 ms.

Check whether the interrupted process is the target kernel thread; ignore if not.

Ensure preempt_cnt is zero and the context is not a soft‑interrupt.

Verify that the current instruction permits an injected schedule.

Save the interrupting process's register state on its kernel stack.

Modify the saved registers so that ip points to a new function.

Return from the interrupt and invoke msleep to actively schedule.

Restore the original registers, completing an artificial msleep ‑induced schedule.

2.2 Diagram

2.3 Detailed Analysis

2.3.1 Clock Interrupt Implementation

The hrtimer API is used to trigger an interrupt every 20 ms. The timer is pinned to each CPU to guarantee per‑CPU execution.

void timer_callback() {
  // Save and modify interrupt registers here
}

void setup_timer() {
  ktime_t interval = ktime_set(0, 20000000); // 20 ms in ns
  hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
  timer.function = &timer_callback;
  hrtimer_start(&timer, interval, HRTIMER_MODE_REL_PINNED);
  hrtimer_forward_now(timer, interval);
  return HRTIMER_RESTART;
}

2.3.2 Reason for Pre‑check

Pre‑emptive scheduling is only allowed when preempt_cnt is zero and the code is not executing in a soft‑interrupt context; otherwise the kernel may be in a non‑preemptible region such as a spin‑lock.

2.3.3 Canary Stack Check

When __stack_chk_fail is triggered, it indicates that the stack canary (saved in flags) was altered, leading to a kernel panic. Therefore the injected code must also preserve the flags register.

__asm__ volatile (
  "addq $1024, %rsp
\t"
  "pushq %r15
\t"
  "subq $1016, %rsp
\t"
  "popq %r15
\t"
  // ... save other registers ...
);

msleep(interval);

__asm__ volatile (
  "popq %r15
\t"
  // ... restore other registers ...
  "popfq
\t"
  "retq
"
);

2.3.4 Hardware Interrupt Specification

During the interrupt, rsp must always point to the lowest valid address on the stack to avoid overwriting data when another interrupt occurs. Non‑maskable interrupts (NMI) have higher priority than regular timer interrupts, so the stack pointer must remain valid throughout both the timer handler and any nested interrupts.

3. Appendix

3.1 kvm Modifications

#undef preempt_disable
#define preempt_disable() do { preempt_count_inc(); barrier(); } while (0)
#undef preempt_enable
#define preempt_enable() do { barrier(); preempt_count_dec(); } while (0)

3.2 Schedule Program

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/smp.h>
#include <linux/io.h>
#include <linux/stacktrace.h>
#include <linux/stop_machine.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/hrtimer.h>
#include <linux/cpu.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <asm/irq_regs.h>
#include <linux/kallsyms.h>

#define DEFAULT_INTERVAL_NS 20000000 // 20 ms
#define NEW_RSP_OFFSET 1024
#define MAX_RIP_COUNT 20

/* ... kernel module implementation that registers the hrtimer, saves/restores registers, and injects new_func ... */

3.3 References

Intel SDM: https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

KernelLinuxVirtualizationKVMhrtimertimer interrupt
Alibaba Cloud Developer
Written by

Alibaba Cloud Developer

Alibaba's official tech channel, featuring all of its technology innovations.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.