drivers/misc/lkdtm/bugs.c

Source file repositories/reference/linux-study-clean/drivers/misc/lkdtm/bugs.c

File Facts

System
Linux kernel
Corpus path
drivers/misc/lkdtm/bugs.c
Extension
.c
Size
22101 bytes
Lines
886
Domain
Driver Families
Bucket
drivers/misc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct lkdtm_list {
	struct list_head node;
};

/*
 * Make sure our attempts to over run the kernel stack doesn't trigger
 * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we
 * recurse past the end of THREAD_SIZE by default.
 */
#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0)
#define REC_STACK_SIZE (_AC(CONFIG_FRAME_WARN, UL) / 2)
#else
#define REC_STACK_SIZE (THREAD_SIZE / 8UL)
#endif
#define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2)

static int recur_count = REC_NUM_DEFAULT;

static DEFINE_SPINLOCK(lock_me_up);

/*
 * Make sure compiler does not optimize this function or stack frame away:
 * - function marked noinline
 * - stack variables are marked volatile
 * - stack variables are written (memset()) and read (buf[..] passed as arg)
 * - function may have external effects (memzero_explicit())
 * - no tail recursion possible
 */
static int noinline recursive_loop(int remaining)
{
	volatile char buf[REC_STACK_SIZE];
	volatile int ret;

	memset((void *)buf, remaining & 0xFF, sizeof(buf));
	if (!remaining)
		ret = 0;
	else
		ret = recursive_loop((int)buf[remaining % sizeof(buf)] - 1);
	memzero_explicit((void *)buf, sizeof(buf));
	return ret;
}

/* If the depth is negative, use the default, otherwise keep parameter. */
void __init lkdtm_bugs_init(int *recur_param)
{
	if (*recur_param < 0)
		*recur_param = recur_count;
	else
		recur_count = *recur_param;
}

static void lkdtm_PANIC(void)
{
	panic("dumptest");
}

static int panic_stop_irqoff_fn(void *arg)
{
	atomic_t *v = arg;

	/*
	 * As stop_machine() disables interrupts, all CPUs within this function
	 * have interrupts disabled and cannot take a regular IPI.
	 *
	 * The last CPU which enters here will trigger a panic, and as all CPUs
	 * cannot take a regular IPI, we'll only be able to stop secondaries if
	 * smp_send_stop() or crash_smp_send_stop() uses an NMI.
	 */
	if (atomic_inc_return(v) == num_online_cpus())
		panic("panic stop irqoff test");

	for (;;)
		cpu_relax();
}

static void lkdtm_PANIC_STOP_IRQOFF(void)
{
	atomic_t v = ATOMIC_INIT(0);
	stop_machine(panic_stop_irqoff_fn, &v, cpu_online_mask);
}

static bool wait_for_panic;

static enum hrtimer_restart panic_in_hardirq(struct hrtimer *timer)
{
	panic("from hard IRQ context");

	wait_for_panic = false;
	return HRTIMER_NORESTART;
}

Annotation

Implementation Notes