code:
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_CLASS_FLASH=y
CONFIG_LEDS_SYSCON=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_BACKLIGHT=y
CONFIG_LEDS_TRIGGER_CPU=y
CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
CONFIG_LEDS_TRIGGER_GPIO=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_ONESHOT=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_NEW_LEDS=y


code:
# This file contains only configs which are required to boot all configurations and get a shell.

## gem5 x86

# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set

## qemu aarch64

# For some reason not selected by the Buildroot kernel config by default as it was for arm,
# and pci modules fail to build. Not that we have PCI working on ARM anyways.
CONFIG_PCI=y

## gem5 aarch64

# Minimal options required to run gem5 aarch64 in addition to QEMU's aarch64 setup.
# Doing such a minimal boot made the gem5 boot 3x faster on the P51, which is awesome.
CONFIG_ATA_PIIX=y
CONFIG_PCI_HOST_GENERIC=y

## qemu aarch64 ext2

# Also requires gem5 aarch64 options.
# Not needed for initrd / initramfs.
CONFIG_VIRTIO_PCI=y

repo_name: liberatehongkong/linux

license: mit


code:
config BR2_PACKAGE_GEM5
	bool "gem5"
	help
	  Only for the m5 guest instrumentation tool of the gem5 system simulator,
	  does not build the simulator itself.

	  http://gem5.org


code:
################################################################################
#
# GEM5
#
################################################################################

GEM5_VERSION = 1.0
GEM5_SITE = $(LKMC_GEM5_SRCDIR)
GEM5_SITE_METHOD = local

ifeq ($(ARCH),x86_64)
ARCH_MAKE = x86
else
ARCH_MAKE = $(ARCH)
endif

define GEM5_BUILD_CMDS
	# TODO cannot use TARGET_CONFIGURE_OPTS here because it overrides the CFLAGS on m5,
	# which have an include. We should patch gem5 to add a += instead of = there.
	cd '$(@D)/util/m5' && $(MAKE) -f 'Makefile.$(ARCH_MAKE)' CC='$(TARGET_CC)' LD='$(TARGET_LD)'
endef

define GEM5_INSTALL_TARGET_CMDS
	$(INSTALL) -D -m 0755 '$(@D)/util/m5/m5' '$(TARGET_DIR)/usr/bin'
endef

$(eval $(generic-package))


code:
config BR2_PACKAGE_KERNEL_MODULES
	bool "kernel_modules"
	depends on BR2_LINUX_KERNEL
	help
		Linux Kernel Module Cheat.


code:
obj-m += $(addsuffix .o, $(notdir $(basename $(filter-out %.mod.c, $(wildcard $(BR2_EXTERNAL_KERNEL_MODULES_PATH)/*.c)))))
ccflags-y := -DDEBUG -g -std=gnu99 -Werror -Wno-declaration-after-statement -Wframe-larger-than=1000000000

.PHONY: all clean

all:
	$(MAKE) -C '/lib/modules/$(shell uname -r)/build' M='$(PWD)' modules

clean:
	$(MAKE) -C '$(LINUX_DIR)' M='$(PWD)' clean


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#anonymous-inode */

#include <linux/anon_inodes.h>
#include <linux/debugfs.h>
#include <linux/errno.h> /* EFAULT */
#include <linux/fs.h>
#include <linux/kernel.h> /* min */
#include <linux/module.h>
#include <linux/printk.h> /* printk */
#include <linux/uaccess.h> /* copy_from_user */

#include "anonymous_inode.h"

static struct dentry *debugfs_file;
static u32 myval = 1;

static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
	char kbuf[9];
	size_t ret;

	ret = snprintf(kbuf, sizeof(kbuf), "%x", myval);
	if (copy_to_user(buf, kbuf, ret)) {
		ret = -EFAULT;
	}
	myval <<= 4;
	if (myval == 0) {
		myval = 1;
	}
	return ret;
}

static const struct file_operations fops_anon = {
	.read = read,
};

static long unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long argp)
{
	int fd;

	switch (cmd) {
		case LKMC_ANONYMOUS_INODE_GET_FD:
			fd = anon_inode_getfd(
				"todo_what_is_this_for",
				&fops_anon,
				NULL,
				O_RDONLY | O_CLOEXEC
			);
			if (copy_to_user((void __user *)argp, &fd, sizeof(fd))) {
				return -EFAULT;
			}
		break;
		default:
			return -EINVAL;
		break;
	}
	return 0;
}

static const struct file_operations fops_ioctl = {
	.owner = THIS_MODULE,
	.unlocked_ioctl = unlocked_ioctl
};

static int myinit(void)
{
	debugfs_file = debugfs_create_file("lkmc_anonymous_inode", 0, NULL, NULL, &fops_ioctl);
	return 0;
}

static void myexit(void)
{
	debugfs_remove(debugfs_file);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
#ifndef IOCTL_H
#define IOCTL_H

#include <linux/ioctl.h>

#define LKMC_ANONYMOUS_INODE_MAGIC 0x33
#define LKMC_ANONYMOUS_INODE_GET_FD _IOR(LKMC_ANONYMOUS_INODE_MAGIC, 0, int)

#endif


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#character-devices */

#include <linux/fs.h> /* register_chrdev, unregister_chrdev */
#include <linux/module.h>
#include <linux/seq_file.h> /* seq_read, seq_lseek, single_release */

#define NAME "lkmc_character_device"

static int major;

static int show(struct seq_file *m, void *v)
{
	seq_printf(m, "abcd");
	return 0;
}

static int open(struct inode *inode, struct  file *file)
{
	return single_open(file, show, NULL);
}

static const struct file_operations fops = {
	.llseek = seq_lseek,
	.open = open,
	.owner = THIS_MODULE,
	.read = seq_read,
	.release = single_release,
};

static int myinit(void)
{
	major = register_chrdev(0, NAME, &fops);
	return 0;
}

static void myexit(void)
{
	unregister_chrdev(major, NAME);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#automatically-create-character-device-file-on-insmod */

#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h> /* register_chrdev, unregister_chrdev */
#include <linux/module.h>
#include <linux/seq_file.h> /* seq_read, seq_lseek, single_release */

#define NAME "lkmc_character_device_create"

static int major = -1;
static struct cdev mycdev;
static struct class *myclass = NULL;

static int show(struct seq_file *m, void *v)
{
	seq_printf(m, "abcd");
	return 0;
}

static int open(struct inode *inode, struct file *file)
{
	return single_open(file, show, NULL);
}

static const struct file_operations fops = {
	.llseek = seq_lseek,
	.open = open,
	.owner = THIS_MODULE,
	.read = seq_read,
	.release = single_release,
};

static void cleanup(int device_created)
{
    if (device_created) {
        device_destroy(myclass, major);
        cdev_del(&mycdev);
    }
    if (myclass)
        class_destroy(myclass);
    if (major != -1)
        unregister_chrdev_region(major, 1);
}

static int myinit(void)
{
    int device_created = 0;

    /* cat /proc/devices */
    if (alloc_chrdev_region(&major, 0, 1, NAME "_proc") < 0)
        goto error;
    /* ls /sys/class */
    if ((myclass = class_create(THIS_MODULE, NAME "_sys")) == NULL)
        goto error;
    /* ls /dev/ */
    if (device_create(myclass, NULL, major, NULL, NAME "_dev") == NULL)
        goto error;
    device_created = 1;
    cdev_init(&mycdev, &fops);
    if (cdev_add(&mycdev, major, 1) == -1)
        goto error;
    return 0;
error:
    cleanup(device_created);
    return -1;
}

static void myexit(void)
{
    cleanup(1);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#debugfs */

#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <uapi/linux/stat.h> /* S_IRUSR */

static struct dentry *dir, *toplevel_file;
static u32 value = 42;

/* This basically re-implents the write operation of debugfs_create_u32,
 * it is just an excuse to illustrate a fop. */
static ssize_t write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
	int ret;
	unsigned long long res;
	/* https://stackoverflow.com/questions/6139493/how-convert-char-to-int-in-linux-kernel */
	ret = kstrtoull_from_user(buf, len, 10, &res);
	if (ret) {
		/* Negative error code. */
		return ret;
	} else {
		value = res;
		*off= len;
		return len;
	}
}

static const struct file_operations fops = {
	.owner = THIS_MODULE,
	.write = write,
};

static int myinit(void)
{
	struct dentry *file;
	dir = debugfs_create_dir("lkmc_debugfs", 0);
	if (!dir) {
		pr_alert("debugfs_create_dir failed");
		return -1;
	}
	file = debugfs_create_u32("myfile", S_IRUSR | S_IWUSR, dir, &value);
	if (!file) {
		pr_alert("debugfs_create_u32 failed");
		return -1;
	}

	/* Created on the toplevel of the debugfs mount,
	 * and with explicit fops instead of a fixed integer value.
	 */
	toplevel_file = debugfs_create_file(
		"lkmc_debugfs_file", S_IWUSR, NULL, NULL, &fops);
	if (!toplevel_file) {
		return -1;
	}
	return 0;
}

static void myexit(void)
{
	debugfs_remove_recursive(dir);
	debugfs_remove(toplevel_file);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#kernel-module-dependencies */

#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/module.h>

u32 lkmc_dep = 0;
EXPORT_SYMBOL(lkmc_dep);
static struct dentry *debugfs_file;

static int myinit(void)
{
	debugfs_file = debugfs_create_u32("lkmc_dep", S_IRUSR | S_IWUSR, NULL, &lkmc_dep);
	return 0;
}

static void myexit(void)
{
	debugfs_remove(debugfs_file);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#kernel-module-dependencies */

#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/module.h>

extern u32 lkmc_dep;
static struct dentry *debugfs_file;

static int myinit(void)
{
	debugfs_file = debugfs_create_u32("lkmc_dep2", S_IRUSR | S_IWUSR, NULL, &lkmc_dep);
	return 0;
}

static void myexit(void)
{
	debugfs_remove(debugfs_file);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#dump_stack */

#include <linux/module.h>
#include <linux/kernel.h>

static int myinit(void)
{
	pr_info("dump_stack myinit\n");
	dump_stack();
	pr_info("dump_stack after\n");
	return 0;
}

static void myexit(void)
{
	pr_info("panic myexit\n");
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code: name: KERNEL_MODULES


code:
################################################################################
#
# kernel_modules
#
################################################################################

KERNEL_MODULES_VERSION = 1.0
KERNEL_MODULES_SITE = $(BR2_EXTERNAL_KERNEL_MODULES_PATH)
KERNEL_MODULES_SITE_METHOD = local

ifeq ($(BR2_PACKAGE_EIGEN),y)
	KERNEL_MODULES_DEPENDENCIES += eigen
endif
ifeq ($(BR2_PACKAGE_LIBDRM),y)
	KERNEL_MODULES_DEPENDENCIES += libdrm
endif
ifeq ($(BR2_PACKAGE_OPENBLAS),y)
	KERNEL_MODULES_DEPENDENCIES += openblas
endif

define KERNEL_MODULES_BUILD_CMDS
	$(MAKE) -C '$(@D)/user' $(TARGET_CONFIGURE_OPTS) \
	  BR2_PACKAGE_EIGEN="$(BR2_PACKAGE_EIGEN)" \
	  BR2_PACKAGE_LIBDRM="$(BR2_PACKAGE_LIBDRM)" \
	  BR2_PACKAGE_OPENBLAS="$(BR2_PACKAGE_OPENBLAS)" \
	;
endef

define KERNEL_MODULES_INSTALL_TARGET_CMDS
	# The modules are already installed by the kernel-module package type
	# under /lib/modules/**, but let's also copy the modules to the root
	# for insmod convenience.
	#
	# Modules can be still be easily inserted with "modprobe module" however.
	$(INSTALL) -D -m 0655 $(@D)/*.ko '$(TARGET_DIR)'
	$(INSTALL) -D -m 0755 $(@D)/user/*.out '$(TARGET_DIR)'
endef

$(eval $(kernel-module))
$(eval $(generic-package))


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#file-operations */

#include <linux/debugfs.h>
#include <linux/errno.h> /* EFAULT */
#include <linux/fs.h> /* file_operations */
#include <linux/kernel.h> /* min */
#include <linux/module.h>
#include <linux/printk.h> /* printk */
#include <linux/uaccess.h> /* copy_from_user, copy_to_user */
#include <uapi/linux/stat.h> /* S_IRUSR */

static struct dentry *debugfs_file;
static char data[] = {'a', 'b', 'c', 'd'};

static int open(struct inode *inode, struct file *filp)
{
	pr_info("open\n");
	return 0;
}

/* @param[in,out] off: gives the initial position into the buffer.
 *      We must increment this by the ammount of bytes read.
 *      Then when userland reads the same file descriptor again,
 *      we start from that point instead.
 */
static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
	ssize_t ret;

	pr_info("read\n");
	pr_info("len = %zu\n", len);
	pr_info("off = %lld\n", (long long)*off);
	if (sizeof(data) <= *off) {
		ret = 0;
	} else {
		ret = min(len, sizeof(data) - (size_t)*off);
		if (copy_to_user(buf, data + *off, ret)) {
			ret = -EFAULT;
		} else {
			*off += ret;
		}
	}
	pr_info("buf = %.*s\n", (int)len, buf);
	pr_info("ret = %lld\n", (long long)ret);
	return ret;
}

/* Similar to read, but with one notable difference:
 * we must return ENOSPC if the user tries to write more
 * than the size of our buffer. Otherwise, Bash > just
 * keeps trying to write to it infinitely.
 */
static ssize_t write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
	ssize_t ret;

	pr_info("write\n");
	pr_info("len = %zu\n", len);
	pr_info("off = %lld\n", (long long)*off);
	if (sizeof(data) <= *off) {
		ret = 0;
	} else {
		if (sizeof(data) - (size_t)*off < len) {
			ret = -ENOSPC;
		} else {
			if (copy_from_user(data + *off, buf, len)) {
				ret = -EFAULT;
			} else {
				ret = len;
				pr_info("buf = %.*s\n", (int)len, data + *off);
				*off += ret;
			}
		}
	}
	pr_info("ret = %lld\n", (long long)ret);
	return ret;
}

/* Called on the last close:
 * http://stackoverflow.com/questions/11393674/why-is-the-close-function-is-called-release-in-struct-file-operations-in-the-l
 */
static int release(struct inode *inode, struct file *filp)
{
	pr_info("release\n");
	return 0;
}

static loff_t llseek(struct file *filp, loff_t off, int whence)
{
	loff_t newpos;

	pr_info("llseek\n");
	pr_info("off = %lld\n", (long long)off);
	pr_info("whence = %lld\n", (long long)whence);
	switch(whence) {
		case SEEK_SET:
			newpos = off;
			break;
		case SEEK_CUR:
			newpos = filp->f_pos + off;
			break;
		case SEEK_END:
			newpos = sizeof(data) + off;
			break;
		default:
			return -EINVAL;
	}
	if (newpos < 0) return -EINVAL;
	filp->f_pos = newpos;
	pr_info("newpos = %lld\n", (long long)newpos);
	return newpos;
}

static const struct file_operations fops = {
	/* Prevents rmmod while fops are running.
	 * Try removing this for poll, which waits a lot. */
	.owner = THIS_MODULE,
	.llseek = llseek,
	.open = open,
	.read = read,
	.release = release,
	.write = write,
};

static int myinit(void)
{
	debugfs_file = debugfs_create_file("lkmc_fops", S_IRUSR | S_IWUSR, NULL, NULL, &fops);
	return 0;
}

static void myexit(void)
{
	debugfs_remove_recursive(debugfs_file);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#getting-started-natively */

#include <linux/module.h>
#include <linux/kernel.h>

static int myinit(void)
{
	pr_info("hello init\n");
	/* 0 for success, any negative value means failure,
	 * E* consts if you want to specify failure cause.
	 * https://www.linux.com/learn/kernel-newbie-corner-loadable-kernel-modules-coming-and-going */
	return 0;
}

static void myexit(void)
{
	pr_info("hello exit\n");
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#getting-started-natively */

#include <linux/module.h>
#include <linux/kernel.h>

static int myinit(void)
{
	pr_info("hello2 init\n");
	return 0;
}

static void myexit(void)
{
	pr_info("hello2 exit\n");
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#init_module */

#include <linux/module.h>
#include <linux/kernel.h>

int init_module(void)
{
	pr_info("init_module\n");
	return 0;
}

void cleanup_module(void)
{
	pr_info("cleanup_module\n");
}
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#ioctl */

#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/printk.h> /* printk */
#include <linux/uaccess.h> /* copy_from_user, copy_to_user */

#include "ioctl.h"

static struct dentry *debugfs_file;

static long unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long argp)
{
	void __user *arg_user;
	union {
		int i;
		lkmc_ioctl_struct s;
	} arg_kernel;

	arg_user = (void __user *)argp;
	pr_info("cmd = %x\n", cmd);
	switch (cmd) {
		case LKMC_IOCTL_INC:
			if (copy_from_user(&arg_kernel.i, arg_user, sizeof(arg_kernel.i))) {
				return -EFAULT;
			}
			pr_info("0 arg = %d\n", arg_kernel.i);
			arg_kernel.i += 1;
			if (copy_to_user(arg_user, &arg_kernel.i, sizeof(arg_kernel.i))) {
				return -EFAULT;
			}
		break;
		case LKMC_IOCTL_INC_DEC:
			if (copy_from_user(&arg_kernel.s, arg_user, sizeof(arg_kernel.s))) {
				return -EFAULT;
			}
			pr_info("1 arg = %d %d\n", arg_kernel.s.i, arg_kernel.s.j);
			arg_kernel.s.i += 1;
			arg_kernel.s.j -= 1;
			if (copy_to_user(arg_user, &arg_kernel.s, sizeof(arg_kernel.s))) {
				return -EFAULT;
			}
		break;
		default:
			return -EINVAL;
		break;
	}
	return 0;
}

static const struct file_operations fops = {
	.owner = THIS_MODULE,
	.unlocked_ioctl = unlocked_ioctl
};

static int myinit(void)
{
	/* ioctl permissions are not automatically restricted by rwx as for read / write,
	 * but we could of course implement that ourselves:
	 * https://stackoverflow.com/questions/29891803/user-permission-check-on-ioctl-command */
	debugfs_file = debugfs_create_file("lkmc_ioctl", 0, NULL, NULL, &fops);
	return 0;
}

static void myexit(void)
{
	debugfs_remove(debugfs_file);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
#ifndef IOCTL_H
#define IOCTL_H

#include <linux/ioctl.h>

/* Structs are the way to pass multiple arguments. */
typedef struct {
	int i;
	int j;
} lkmc_ioctl_struct;

/* TODO some random number I can't understand how to choose. */
#define LKMC_IOCTL_MAGIC 0x33

/* I think those number do not *need* to be unique across, that is just to help debugging:
 * https://stackoverflow.com/questions/22496123/what-is-the-meaning-of-this-macro-iormy-macig-0-int
 *
 * However, the ioctl syscall highjacks several low values at do_vfs_ioctl, e.g.
 * This "forces" use to use the _IOx macros...
 * https://stackoverflow.com/questions/10071296/ioctl-is-not-called-if-cmd-2
 *
 * Some of those magic low values are used for fnctl, which can also be used on regular files:
 * e.g. FIOCLEX for close-on-exec:
 * https://stackoverflow.com/questions/6125068/what-does-the-fd-cloexec-fcntl-flag-do
 *
 * TODO are the W or R of _IOx and type functional, or only to help with uniqueness?
 *
 * Documentation/ioctl/ioctl-number.txt documents:
 *
 * ....
 * _IO    an ioctl with no parameters
 * _IOW   an ioctl with write parameters (copy_from_user)
 * _IOR   an ioctl with read parameters  (copy_to_user)
 * _IOWR  an ioctl with both write and read parameters.
 * ....
 */
/* Take an int, increment it. */
#define LKMC_IOCTL_INC     _IOWR(LKMC_IOCTL_MAGIC, 0, int)
/* Take a struct with two ints, increment the first, and decrement the second. */
#define LKMC_IOCTL_INC_DEC _IOWR(LKMC_IOCTL_MAGIC, 1, lkmc_ioctl_struct)

#endif


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#irq-ko */

#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/uaccess.h> /* copy_from_user, copy_to_user */

#define NAME "lkmc_irq"
#define MAX_IRQS 256

static int irqs[MAX_IRQS];
static int major;

/**
 * Return value from kernel docs:*
 *
 * enum irqreturn
 * @IRQ_NONE        interrupt was not from this device or was not handled
 * @IRQ_HANDLED     interrupt was handled by this device
 * @IRQ_WAKE_THREAD handler requests to wake the handler thread
 */
static irqreturn_t handler(int irq, void *dev)
{
	pr_info("handler irq = %d dev = %d\n", irq, *(int *)dev);
	return IRQ_NONE;
}

static const struct file_operations fops;

static int myinit(void)
{
	int ret, i;

	major = register_chrdev(0, NAME, &fops);
	for (i = 0; i < MAX_IRQS; ++i) {
		ret = request_irq(
			i,
			handler,
			IRQF_SHARED,
			"myirqhandler0",
			&major
		);
		irqs[i] = ret;
		pr_info("request_irq irq = %d ret = %d\n", i, ret);
	}
	return 0;
}

static void myexit(void)
{
	int i;

	for (i = 0; i < MAX_IRQS; ++i) {
		if (!irqs[i]) {
			free_irq(i, &major);
		}
	}
	unregister_chrdev(major, NAME);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#kprobes
 *
 * Adapted from: https://github.com/torvalds/linux/blob/v4.17/samples/kprobes/kprobe_example.c
 */

/*
 * NOTE: This example is works on x86 and powerpc.
 * Here's a sample kernel module showing the use of kprobes to dump a
 * stack trace and selected registers when _do_fork() is called.
 *
 * For more information on theory of operation of kprobes, see
 * Documentation/kprobes.txt
 *
 * You will see the trace data in /var/log/messages and on the console
 * whenever _do_fork() is invoked to create a new process.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>

#define MAX_SYMBOL_LEN	64
static char symbol[MAX_SYMBOL_LEN] = "_do_fork";
module_param_string(symbol, symbol, sizeof(symbol), 0644);

/* For each probe you need to allocate a kprobe structure */
static struct kprobe kp = {
	.symbol_name	= symbol,
};

/* kprobe pre_handler: called just before the probed instruction is executed */
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
#ifdef CONFIG_X86
	pr_info("<%s> pre_handler: p->addr = 0x%px, ip = %lx, flags = 0x%lx\n",
		p->symbol_name, p->addr, regs->ip, regs->flags);
#endif
#ifdef CONFIG_PPC
	pr_info("<%s> pre_handler: p->addr = 0x%px, nip = 0x%lx, msr = 0x%lx\n",
		p->symbol_name, p->addr, regs->nip, regs->msr);
#endif
#ifdef CONFIG_MIPS
	pr_info("<%s> pre_handler: p->addr = 0x%px, epc = 0x%lx, status = 0x%lx\n",
		p->symbol_name, p->addr, regs->cp0_epc, regs->cp0_status);
#endif
#ifdef CONFIG_ARM64
	pr_info("<%s> pre_handler: p->addr = 0x%px, pc = 0x%lx,"
			" pstate = 0x%lx\n",
		p->symbol_name, p->addr, (long)regs->pc, (long)regs->pstate);
#endif
#ifdef CONFIG_S390
	pr_info("<%s> pre_handler: p->addr, 0x%px, ip = 0x%lx, flags = 0x%lx\n",
		p->symbol_name, p->addr, regs->psw.addr, regs->flags);
#endif

	/* A dump_stack() here will give a stack backtrace */
	return 0;
}

/* kprobe post_handler: called after the probed instruction is executed */
static void handler_post(struct kprobe *p, struct pt_regs *regs,
				unsigned long flags)
{
#ifdef CONFIG_X86
	pr_info("<%s> post_handler: p->addr = 0x%px, flags = 0x%lx\n",
		p->symbol_name, p->addr, regs->flags);
#endif
#ifdef CONFIG_PPC
	pr_info("<%s> post_handler: p->addr = 0x%px, msr = 0x%lx\n",
		p->symbol_name, p->addr, regs->msr);
#endif
#ifdef CONFIG_MIPS
	pr_info("<%s> post_handler: p->addr = 0x%px, status = 0x%lx\n",
		p->symbol_name, p->addr, regs->cp0_status);
#endif
#ifdef CONFIG_ARM64
	pr_info("<%s> post_handler: p->addr = 0x%px, pstate = 0x%lx\n",
		p->symbol_name, p->addr, (long)regs->pstate);
#endif
#ifdef CONFIG_S390
	pr_info("<%s> pre_handler: p->addr, 0x%px, flags = 0x%lx\n",
		p->symbol_name, p->addr, regs->flags);
#endif
}

/*
 * fault_handler: this is called if an exception is generated for any
 * instruction within the pre- or post-handler, or when Kprobes
 * single-steps the probed instruction.
 */
static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
{
	pr_info("fault_handler: p->addr = 0x%px, trap #%dn", p->addr, trapnr);
	/* Return 0 because we don't handle the fault. */
	return 0;
}

static int __init kprobe_init(void)
{
	int ret;
	kp.pre_handler = handler_pre;
	kp.post_handler = handler_post;
	kp.fault_handler = handler_fault;

	ret = register_kprobe(&kp);
	if (ret < 0) {
		pr_err("register_kprobe failed, returned %d\n", ret);
		return ret;
	}
	pr_info("Planted kprobe at %px\n", kp.addr);
	return 0;
}

static void __exit kprobe_exit(void)
{
	unregister_kprobe(&kp);
	pr_info("kprobe at %px unregistered\n", kp.addr);
}

module_init(kprobe_init)
module_exit(kprobe_exit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#kstrto */

#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h> /* copy_from_user, copy_to_user */
#include <uapi/linux/stat.h> /* S_IWUSR */

static struct dentry *toplevel_file;
static char read_buf[1024];

static int show(struct seq_file *m, void *v)
{
	seq_printf(m, read_buf);
	return 0;
}

static int open(struct inode *inode, struct file *file)
{
	return single_open(file, show, NULL);
}

static ssize_t write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
	ssize_t ret;
	int kstrto_return;
	unsigned long long kstrto_result;
	kstrto_return = kstrtoull_from_user(buf, len, 10, &kstrto_result);
	if (kstrto_return) {
		/* Negative error code. */
		ret = kstrto_return;
	} else {
		ret = len;
	}
	snprintf(read_buf, sizeof(read_buf), "%llu", kstrto_result + 1);
	return ret;
}

static const struct file_operations fops = {
	.llseek = seq_lseek,
	.open = open,
	.owner = THIS_MODULE,
	.read = seq_read,
	.release = single_release,
	.write = write,
};

static int myinit(void)
{
	toplevel_file = debugfs_create_file("lkmc_kstrto", S_IWUSR, NULL, NULL, &fops);
	if (!toplevel_file) {
		return -1;
	}
	return 0;
}

static void myexit(void)
{
	debugfs_remove(toplevel_file);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#kthread */

#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>

static struct task_struct *kthread;

static int work_func(void *data)
{
	u32 i = 0;
	while (!kthread_should_stop()) {
		pr_info("%u\n", i);
		usleep_range(1000000, 1000001);
		i++;
		if (i == 10)
			i = 0;
	}
	return 0;
}

static int myinit(void)
{
	kthread = kthread_create(work_func, NULL, "mykthread");
	wake_up_process(kthread);
	return 0;
}

static void myexit(void)
{
	/* Waits for thread to return. */
	kthread_stop(kthread);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#kthreads */

#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>

static struct task_struct *kthread1, *kthread2;

static int work_func1(void *data)
{
	int i = 0;
	while (!kthread_should_stop()) {
		pr_info("1 %d\n", i);
		usleep_range(1000000, 1000001);
		i++;
		if (i == 10)
			i = 0;
	}
	return 0;
}

static int work_func2(void *data)
{
	int i = 0;
	while (!kthread_should_stop()) {
		pr_info("2 %d\n", i);
		usleep_range(1000000, 1000001);
		i++;
		if (i == 10)
			i = 0;
	}
	return 0;
}

static int myinit(void)
{
	kthread1 = kthread_create(work_func1, NULL, "mykthread1");
	kthread2 = kthread_create(work_func2, NULL, "mykthread2");
	wake_up_process(kthread1);
	wake_up_process(kthread2);
	return 0;
}

static void myexit(void)
{
	kthread_stop(kthread1);
	kthread_stop(kthread2);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
#!/usr/bin/env bash

# We can almost do everything from the Makefile itself by using default values for
#
#    LINUX_DIR ?= "/lib/modules/$(uname -r)/build"
#    BR2_EXTERNAL_KERNEL_MODULES_PATH="$(pwd)"
#
# The problem with that is that if you define those variables in your environment,
# the build breaks, so this is more portable.
#
# Trying to add `-i` to overcome incompatible modules will fail,
# because any build failure prevents the generation of all `.mod.c` files.

j="$(($(nproc) - 2))"
while getopts j: OPT; do
  case "$OPT" in
    'j')
      j="$OPTARG"
    ;;
  esac
done
shift $(($OPTIND - 1))
make -j "$j" KERNEL_MODULES_PATH="$(pwd)" LINUX_DIR="/lib/modules/$(uname -r)/build" "$@"
make -C user/ -j "$j" "$@"


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#config_fortify_source */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/slab.h>

static int myinit(void)
{
	void *dst, *src;
    dst = kmalloc(0x10, GFP_KERNEL);
    src = kmalloc(0x1000000, GFP_KERNEL);
	memcpy(dst, src, 0x1000000);
	return 0;
}

static void myexit(void) {}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#mmap */

#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h> /* min */
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h> /* copy_from_user, copy_to_user */
#include <linux/slab.h>

static const char *filename = "lkmc_mmap";

enum { BUFFER_SIZE = 4 };

struct mmap_info {
	char *data;
};

/* After unmap. */
static void vm_close(struct vm_area_struct *vma)
{
	pr_info("vm_close\n");
}

/* First page access. */
	int (*fault)(struct vm_fault *vmf);
static int vm_fault(struct vm_fault *vmf)
{
	struct page *page;
	struct mmap_info *info;

	pr_info("vm_fault\n");
	info = (struct mmap_info *)vmf->vma->vm_private_data;
	if (info->data) {
		page = virt_to_page(info->data);
		get_page(page);
		vmf->page = page;
	}
	return 0;
}

/* Aftr mmap. TODO vs mmap, when can this happen at a different time than mmap? */
static void vm_open(struct vm_area_struct *vma)
{
	pr_info("vm_open\n");
}

static struct vm_operations_struct vm_ops =
{
	.close = vm_close,
	.fault = vm_fault,
	.open = vm_open,
};

static int mmap(struct file *filp, struct vm_area_struct *vma)
{
	pr_info("mmap\n");
	vma->vm_ops = &vm_ops;
	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
	vma->vm_private_data = filp->private_data;
	vm_open(vma);
	return 0;
}

static int open(struct inode *inode, struct file *filp)
{
	struct mmap_info *info;

	pr_info("open\n");
	info = kmalloc(sizeof(struct mmap_info), GFP_KERNEL);
	pr_info("virt_to_phys = 0x%llx\n", (unsigned long long)virt_to_phys((void *)info));
	info->data = (char *)get_zeroed_page(GFP_KERNEL);
	memcpy(info->data, "asdf", BUFFER_SIZE);
	filp->private_data = info;
	return 0;
}

static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
	struct mmap_info *info;
    int ret;

	pr_info("read\n");
	info = filp->private_data;
    ret = min(len, (size_t)BUFFER_SIZE);
    if (copy_to_user(buf, info->data, ret)) {
        ret = -EFAULT;
	}
	return ret;
}

static ssize_t write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
	struct mmap_info *info;

	pr_info("write\n");
	info = filp->private_data;
    if (copy_from_user(info->data, buf, min(len, (size_t)BUFFER_SIZE))) {
        return -EFAULT;
    } else {
        return len;
    }
}

static int release(struct inode *inode, struct file *filp)
{
	struct mmap_info *info;

	pr_info("release\n");
	info = filp->private_data;
	free_page((unsigned long)info->data);
	kfree(info);
	filp->private_data = NULL;
	return 0;
}

static const struct file_operations fops = {
	.mmap = mmap,
	.open = open,
	.release = release,
	.read = read,
	.write = write,
};

static int myinit(void)
{
	proc_create(filename, 0, NULL, &fops);
	return 0;
}

static void myexit(void)
{
	remove_proc_entry(filename, NULL);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#module_info */

#include <linux/module.h>
#include <linux/kernel.h>

static int myinit(void)
{
	/* Set by default based on the module file name. */
	pr_info("name = %s\n", THIS_MODULE->name);
	pr_info("version = %s\n", THIS_MODULE->version);
	/* ERROR: nope, not part of struct module. */
	/*pr_info("asdf = %s\n", THIS_MODULE->asdf);*/
	return 0;
}

static void myexit(void) {}

module_init(myinit)
module_exit(myexit)
MODULE_INFO(asdf, "qwer");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#pr_debug */

#include <linux/module.h>
#include <linux/kernel.h>

static int myinit(void)
{
	pr_alert("pr_alert\n");
	pr_crit("pr_crit\n");
	pr_err("pr_err");
	pr_warning("pr_warning\n");
	pr_notice("pr_notice\n");
	pr_info("pr_info\n");
	pr_debug("pr_debug\n");
	return 0;
}

static void myexit(void) { }

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#netlink-sockets */

#include <linux/delay.h> /* usleep_range */
#include <linux/module.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <net/sock.h>

#include "netlink.h"

struct sock *nl_sk = NULL;

static u32 count;
static u32 sleep;
module_param(sleep, int, S_IRUSR | S_IWUSR);

static void callback(struct sk_buff *skb)
{
	char readbuf[9];
	size_t readbuflen;
    int pid;
    int res;
    struct nlmsghdr *nlh;
    struct sk_buff *skb_out;

    nlh = (struct nlmsghdr *)skb->data;
    pr_info("kernel received: %s\n", (char *)nlmsg_data(nlh));
	if (sleep)
		usleep_range(1000000, 1000001);
	readbuflen = snprintf(readbuf, sizeof(readbuf), "%x", count);
    count++;
    pid = nlh->nlmsg_pid;
    skb_out = nlmsg_new(readbuflen, 0);
    if (!skb_out) {
        pr_err("nlmsg_new\n");
        return;
    }
    nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, readbuflen, 0);
    NETLINK_CB(skb_out).dst_group = 0;
    strncpy(nlmsg_data(nlh), readbuf, readbuflen);
    res = nlmsg_unicast(nl_sk, skb_out, pid);
    if (res < 0)
        pr_info("nlmsg_unicast\n");
}

static int myinit(void)
{
    struct netlink_kernel_cfg cfg = {
        .input = callback,
    };
    nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
    if (!nl_sk) {
        pr_err("netlink_kernel_create\n");
        return -10;
    }
    return 0;
}

static void myexit(void)
{
    netlink_kernel_release(nl_sk);
}

module_init(myinit);
module_exit(myexit);
MODULE_LICENSE("GPL");


code:
#ifndef NETLINK_H
#define NETLINK_H

/* Socket identifier, matches userland. TODO can be anything?
 * Is there a more scalable way to do it? E.g. ioctl device,
 * kernel generates one on the fly, then give it back and connect?
 * https://stackoverflow.com/questions/32898173/can-i-have-more-than-32-netlink-sockets-in-kernelspace */
#define NETLINK_USER 31

#endif


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#kernel-panic-and-oops */

#include <linux/module.h>
#include <linux/kernel.h>

static int myinit(void)
{
	pr_info("oops myinit\n");
	*(int *)0 = 0;
	pr_info("oops after\n");
	return 0;
}

static void myexit(void)
{
	pr_info("oops myexit\n");
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#kernel-panic-and-oops */

#include <linux/module.h>
#include <linux/kernel.h>

static int myinit(void)
{
	pr_info("panic myinit\n");
	panic("hello panic");
	pr_info("panic after\n");
	return 0;
}

static void myexit(void)
{
	pr_info("panic myexit\n");
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#kernel-module-parameters */

#include <linux/debugfs.h>
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/seq_file.h> /* seq_read, seq_lseek, single_release */
#include <uapi/linux/stat.h> /* S_IRUSR | S_IWUSR */

static u32 i = 0;
static u32 j = 0;
module_param(i, int, S_IRUSR | S_IWUSR);
module_param(j, int, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC(i, "my favorite int");
MODULE_PARM_DESC(j, "my second favorite int");

static struct dentry *debugfs_file;

static int show(struct seq_file *m, void *v)
{
	char kbuf[18];
	int ret;

	ret = snprintf(kbuf, sizeof(kbuf), "%d %d", i, j);
	seq_printf(m, kbuf);
	return 0;
}

static int open(struct inode *inode, struct file *file)
{
	return single_open(file, show, NULL);
}

static const struct file_operations fops = {
	.llseek = seq_lseek,
	.open = open,
	.owner = THIS_MODULE,
	.read = seq_read,
	.release = single_release,
};

static int myinit(void)
{
	debugfs_file = debugfs_create_file("lkmc_params", S_IRUSR, NULL, NULL, &fops);
	return 0;
}

static void myexit(void)
{
	debugfs_remove(debugfs_file);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#pci_min */

#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/uaccess.h> /* copy_from_user, copy_to_user */

#define BAR 0
#define CDEV_NAME "lkmc_hw_pci_min"
#define EDU_DEVICE_ID 0x11e9
#define QEMU_VENDOR_ID 0x1234

static struct pci_device_id id_table[] = {
    { PCI_DEVICE(QEMU_VENDOR_ID, EDU_DEVICE_ID), },
    { 0, }
};
MODULE_DEVICE_TABLE(pci, id_table);
static int major;
static struct pci_dev *pdev;
static void __iomem *mmio;
static struct file_operations fops = {
    .owner   = THIS_MODULE,
};

static irqreturn_t irq_handler(int irq, void *dev)
{
    pr_info("irq_handler irq = %d dev = %d\n", irq, *(int *)dev);
    iowrite32(0, mmio + 4);
    return IRQ_HANDLED;
}

static int probe(struct pci_dev *dev, const struct pci_device_id *id)
{
    pr_info("probe\n");
    major = register_chrdev(0, CDEV_NAME, &fops);
    pdev = dev;
    if (pci_enable_device(dev) < 0) {
        dev_err(&(pdev->dev), "pci_enable_device\n");
        goto error;
    }
    if (pci_request_region(dev, BAR, "myregion0")) {
        dev_err(&(pdev->dev), "pci_request_region\n");
        goto error;
    }
    mmio = pci_iomap(pdev, BAR, pci_resource_len(pdev, BAR));
    pr_info("dev->irq = %u\n", dev->irq);
    if (request_irq(dev->irq, irq_handler, IRQF_SHARED, "pci_irq_handler0", &major) < 0) {
        dev_err(&(dev->dev), "request_irq\n");
        goto error;
    }
    iowrite32(0x12345678, mmio);
    return 0;
error:
    return 1;
}

static void remove(struct pci_dev *dev)
{
    pr_info("remove\n");
    free_irq(dev->irq, &major);
    pci_release_region(dev, BAR);
    unregister_chrdev(major, CDEV_NAME);
}

static struct pci_driver pci_driver = {
    .name     = CDEV_NAME,
    .id_table = id_table,
    .probe    = probe,
    .remove   = remove,
};

static int myinit(void)
{
    if (pci_register_driver(&pci_driver) < 0) {
        return 1;
    }
    return 0;
}

static void myexit(void)
{
    pci_unregister_driver(&pci_driver);
}

module_init(myinit);
module_exit(myexit);
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#pmccntr */

#include <linux/debugfs.h>
#include <linux/errno.h> /* EFAULT */
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/printk.h> /* pr_info */
#include <linux/seq_file.h> /* seq_read, seq_lseek, single_release */
#include <linux/uaccess.h> /* copy_from_user, copy_to_user */
#include <uapi/linux/stat.h> /* S_IRUSR */

static struct dentry *debugfs_file;

static int show(struct seq_file *m, void *v)
{
	u32 pmccntr;
#if defined(__arm__)
	/* Invalid aarch64 asm. */

	/* TODO  Internal error: Oops - undefined instruction: 0 [#1] ARM */
	/* Enable userland access to conter. */
	/* PMUSERENR = 1 */
	/*__asm__ __volatile__ ("mcr p15, 0, %0, c9, c14, 0" :: "r"(1));*/

	/* TODO oops undefined instruction. */
	/* PMCR.E (bit 0) = 1 */
	/*__asm__ __volatile__ ("mcr p15, 0, %0, c9, c12, 0" :: "r"(1));*/

	/* TODO oops undefined instruction. */
	/* Enable counter. */
	/* PMCNTENSET.C (bit 31) = 1 */
	/*__asm__ __volatile__ ("mcr p15, 0, %0, c9, c12, 1" :: "r"(1 << 31));*/

	/* Get counter value. */
	__asm__ __volatile__ ("mrc p15, 0, %0, c15, c12, 1" : "=r" (pmccntr));
#else
	pmccntr = 0;
#endif
	seq_printf(m, "%8.8llX\n", (unsigned long long)pmccntr);
	return 0;
}

static int open(struct inode *inode, struct file *file)
{
	return single_open(file, show, NULL);
}

static const struct file_operations fops = {
	.llseek = seq_lseek,
	.open = open,
	.owner = THIS_MODULE,
	.read = seq_read,
	.release = single_release,
};

static int myinit(void)
{
	debugfs_file = debugfs_create_file("lkmc_pmccntr", S_IRUSR, NULL, NULL, &fops);
	if (!debugfs_file) {
		return -1;
	}
	return 0;
}

static void myexit(void)
{
	debugfs_remove(debugfs_file);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#poll */

#include <linux/debugfs.h>
#include <linux/delay.h> /* usleep_range */
#include <linux/errno.h> /* EFAULT */
#include <linux/fs.h>
#include <linux/jiffies.h>
#include <linux/kernel.h> /* min */
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/printk.h> /* printk */
#include <linux/uaccess.h> /* copy_from_user, copy_to_user */
#include <linux/wait.h> /* wait_queue_head_t, wait_event_interruptible, wake_up_interruptible  */
#include <uapi/linux/stat.h> /* S_IRUSR */

static char readbuf[1024];
static size_t readbuflen;
static struct dentry *debugfs_file;
static struct task_struct *kthread;
static wait_queue_head_t waitqueue;

static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
	ssize_t ret;
	if (copy_to_user(buf, readbuf, readbuflen)) {
		ret = -EFAULT;
	} else {
		ret = readbuflen;
	}
	/* This is normal pipe behaviour: data gets drained once a reader reads from it. */
	/* https://stackoverflow.com/questions/1634580/named-pipes-fifos-on-unix-with-multiple-readers */
	readbuflen = 0;
	return ret;
}

/* If you return 0 here, then the kernel will sleep until an event happens in the queue.
 *
 * This gets called again every time an event happens in the wait queue.
 */
unsigned int poll(struct file *filp, struct poll_table_struct *wait)
{
	poll_wait(filp, &waitqueue, wait);
	if (readbuflen)
		return POLLIN;
	else
		return 0;
}

static int kthread_func(void *data)
{
	while (!kthread_should_stop()) {
		readbuflen = snprintf(readbuf, sizeof(readbuf), "%llu", (unsigned long long)jiffies);
		usleep_range(1000000, 1000001);
		wake_up(&waitqueue);
	}
	return 0;
}

static const struct file_operations fops = {
	.owner = THIS_MODULE,
	.read = read,
	.poll = poll
};

static int myinit(void)
{
	debugfs_file = debugfs_create_file(
		"lkmc_poll", S_IRUSR | S_IWUSR, NULL, NULL, &fops);
	init_waitqueue_head(&waitqueue);
	kthread = kthread_create(kthread_func, NULL, "mykthread");
	wake_up_process(kthread);
	return 0;
}

static void myexit(void)
{
	kthread_stop(kthread);
	debugfs_remove(debugfs_file);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#procfs */

#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h> /* seq_read, seq_lseek, single_open, single_release */
#include <uapi/linux/stat.h> /* S_IRUSR */

static const char *filename = "lkmc_procfs";

static int show(struct seq_file *m, void *v)
{
	seq_printf(m, "abcd\n");
	return 0;
}

static int open(struct inode *inode, struct  file *file)
{
	return single_open(file, show, NULL);
}

static const struct file_operations fops = {
	.llseek = seq_lseek,
	.open = open,
	.owner = THIS_MODULE,
	.read = seq_read,
	.release = single_release,
};

static int myinit(void)
{
	proc_create(filename, 0, NULL, &fops);
	return 0;
}

static void myexit(void)
{
	remove_proc_entry(filename, NULL);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#qemu-edu */

#include <linux/cdev.h> /* cdev_ */
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/uaccess.h> /* put_user */

#define BAR 0
#define CDEV_NAME "lkmc_pci"
#define EDU_DEVICE_ID 0x11e8
#define QEMU_VENDOR_ID 0x1234

/* Registers. */
#define IO_IRQ_STATUS 0x24
#define IO_IRQ_ACK 0x64
#define IO_DMA_SRC 0x80
#define IO_DMA_DST 0x88
#define IO_DMA_CNT 0x90
#define IO_DMA_CMD 0x98

/* Constants. */
/* TODO what is this magic value for? Can't it be always deduced from the direction? */
#define DMA_BASE 0x40000
/* Must give this for the DMA command to to anything. */
#define DMA_CMD 0x1
/* If given, device -> RAM. Otherwise: RAM -> dev. */
#define DMA_FROM_DEV 0x2
/* If given, raise an IRQ, and write 100 to the IRQ status register. */
#define DMA_IRQ 0x4

static struct pci_device_id pci_ids[] = {
	{ PCI_DEVICE(QEMU_VENDOR_ID, EDU_DEVICE_ID), },
	{ 0, }
};
MODULE_DEVICE_TABLE(pci, pci_ids);

static int major;
static struct pci_dev *pdev;
static void __iomem *mmio;

static irqreturn_t irq_handler(int irq, void *dev)
{
	int devi;
	irqreturn_t ret;
	u32 irq_status;

	devi = *(int *)dev;
	if (devi == major) {
		irq_status = ioread32(mmio + IO_IRQ_STATUS);
		pr_info("irq_handler irq = %d dev = %d irq_status = %llx\n",
				irq, devi, (unsigned long long)irq_status);
		/* Must do this ACK, or else the interrupts just keeps firing. */
		iowrite32(irq_status, mmio + IO_IRQ_ACK);
		ret = IRQ_HANDLED;
	} else {
		ret = IRQ_NONE;
	}
	return ret;
}

static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
	ssize_t ret;
	u32 kbuf;

	if (*off % 4 || len == 0) {
		ret = 0;
	} else {
		kbuf = ioread32(mmio + *off);
		if (copy_to_user(buf, (void *)&kbuf, 4)) {
			ret = -EFAULT;
		} else {
			ret = 4;
			(*off)++;
		}
	}
	return ret;
}

static ssize_t write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
	ssize_t ret;
	u32 kbuf;

	ret = len;
	if (!(*off % 4)) {
		if (copy_from_user((void *)&kbuf, buf, 4) || len != 4) {
			ret = -EFAULT;
		} else {
			iowrite32(kbuf, mmio + *off);
		}
	}
	return ret;
}

static loff_t llseek(struct file *filp, loff_t off, int whence)
{
	filp->f_pos = off;
	return off;
}

/* These fops are a bit daft since read and write interfaces don't map well to IO registers.
 *
 * One ioctl per register would likely be the saner option. But we are lazy.
 *
 * We use the fact that every IO is aligned to 4 bytes. Misaligned reads means EOF. */
static struct file_operations fops = {
	.owner   = THIS_MODULE,
	.llseek  = llseek,
	.read    = read,
	.write   = write,
};

/* https://stackoverflow.com/questions/5059501/probe-method-device-drivers/44739823#44739823
 *
 * Called just after insmod if the hardware device is connected,
 * not called otherwise.
 *
 * 0: all good
 * 1: failed
 */
static int pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
	/* https://stackoverflow.com/questions/31382803/how-does-dev-family-functions-are-useful-while-debugging-kernel/44734857#44734857 */
	dev_info(&(dev->dev), "pci_probe\n");
	major = register_chrdev(0, CDEV_NAME, &fops);
	pdev = dev;
	if (pci_enable_device(dev) < 0) {
		dev_err(&(dev->dev), "pci_enable_device\n");
		goto error;
	}
	if (pci_request_region(dev, BAR, "myregion0")) {
		dev_err(&(dev->dev), "pci_request_region\n");
		goto error;
	}
	mmio = pci_iomap(dev, BAR, pci_resource_len(dev, BAR));

	/* IRQ setup.
	 *
	 * pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &val);
	 * has a different value and does not work if we insert the PCI device
	 * after boot with device_add:
	 * https://stackoverflow.com/questions/44740254/how-to-handle-interrupts-from-a-pci-device-that-already-have-a-non-shareable-han?noredirect=1#comment76558680_44740254
	 */
	if (request_irq(dev->irq, irq_handler, IRQF_SHARED, "pci_irq_handler0", &major) < 0) {
		dev_err(&(dev->dev), "request_irq\n");
		goto error;
	}

	/* Optional sanity checks. The PCI is ready now, all of this could also be called from fops. */
	{
		unsigned i;
		u8 val;

		/* Check that we are using MEM instead of IO.
		 *
		 * In QEMU, the type is defiened by either:
		 *
		 * - PCI_BASE_ADDRESS_SPACE_IO
		 * - PCI_BASE_ADDRESS_SPACE_MEMORY
		 */
		if ((pci_resource_flags(dev, BAR) & IORESOURCE_MEM) != IORESOURCE_MEM) {
			dev_err(&(dev->dev), "pci_resource_flags\n");
			goto error;
		}

		/* 1Mb, as defined by the "1 << 20" in QEMU's memory_region_init_io. Same as pci_resource_len. */
		resource_size_t start = pci_resource_start(dev, BAR);
		resource_size_t end = pci_resource_end(dev, BAR);
		pr_info("length %llx\n", (unsigned long long)(end + 1 - start));

		/* The PCI standardized 64 bytes of the configuration space, see LDD3. */
		for (i = 0; i < 64u; ++i) {
			pci_read_config_byte(dev, i, &val);
			pr_info("config %x %x\n", i, val);
		}
		pr_info("dev->irq %x\n", dev->irq);

		/* Initial value of the IO memory. */
		for (i = 0; i < 0x28; i += 4) {
			pr_info("io %x %x\n", i, ioread32((void*)(mmio + i)));
		}

		/* DMA test.
		 *
		 * TODO:
		 *
		 * - deal with interrupts properly.
		 * - printf / gdb in QEMU source says dma_buf is not being set correctly
		 *
		 * Resources:
		 *
		 * - http://elixir.free-electrons.com/linux/v4.12/source/Documentation/DMA-API-HOWTO.txt
		 * - http://www.makelinux.net/ldd3/chp-15-sect-4
		 * - https://stackoverflow.com/questions/32592734/are-there-any-dma-linux-kernel-driver-example-with-pcie-for-fpga/44716747#44716747
		 * - https://stackoverflow.com/questions/17913679/how-to-instantiate-and-use-a-dma-driver-linux-module
		 * - https://stackoverflow.com/questions/5539375/linux-kernel-device-driver-to-dma-from-a-device-into-user-space-memory
		 * - RPI userland /dev/mem https://github.com/Wallacoloo/Raspberry-Pi-DMA-Example
		 * - https://stackoverflow.com/questions/34188369/easiest-way-to-use-dma-in-linux
		 */
		{
			dma_addr_t dma_handle_from, dma_handle_to;
			void *vaddr_from, *vaddr_to;
			enum { SIZE = 4 };

			/* RAM -> device. */
			vaddr_from = dma_alloc_coherent(&(dev->dev), 4, &dma_handle_from, GFP_ATOMIC);
			dev_info(&(dev->dev), "vaddr_from = %px\n", vaddr_from);
			dev_info(&(dev->dev), "dma_handle_from = %llx\n", (unsigned long long)dma_handle_from);
			*((volatile u32*)vaddr_from) = 0x12345678;
			iowrite32((u32)dma_handle_from, mmio + IO_DMA_SRC);
			iowrite32(DMA_BASE, mmio + IO_DMA_DST);
			iowrite32(SIZE, mmio + IO_DMA_CNT);
			iowrite32(DMA_CMD | DMA_IRQ, mmio + IO_DMA_CMD);

			/* device -> RAM. */
			vaddr_to = dma_alloc_coherent(&(dev->dev), 4, &dma_handle_to, GFP_ATOMIC);
			dev_info(&(dev->dev), "vaddr_to = %px\n", vaddr_to);
			dev_info(&(dev->dev), "dma_handle_to = %llx\n", (unsigned long long)dma_handle_to);
			/*
			iowrite32(DMA_BASE, mmio + IO_DMA_SRC);
			iowrite32((u32)dma_handle_to, mmio + IO_DMA_DST);
			iowrite32(SIZE, mmio + IO_DMA_CNT);
			iowrite32(DMA_CMD | DMA_FROM_DEV | DMA_IRQ, mmio + IO_DMA_CMD);
			dev_info(&(dev->dev), "*vaddr_to = %llx\n", (unsigned long long)(*((u32*)vaddr_to)));
			*/

			/*dma_free_coherent(&(dev->dev), SIZE, vaddr_from, dma_handle_from);*/
			/*dma_free_coherent(&(dev->dev), SIZE, vaddr_to, dma_handle_to);*/
		}
	}
	return 0;
error:
	return 1;
}

static void pci_remove(struct pci_dev *dev)
{
	pr_info("pci_remove\n");
	free_irq(pdev->irq, &major);
	pci_release_region(dev, BAR);
	unregister_chrdev(major, CDEV_NAME);
}

static struct pci_driver pci_driver = {
	.name     = "lkmc_pci",
	.id_table = pci_ids,
	.probe    = pci_probe,
	.remove   = pci_remove,
};

static int myinit(void)
{
	if (pci_register_driver(&pci_driver) < 0) {
		return 1;
	}
	return 0;
}

static void myexit(void)
{
	pci_unregister_driver(&pci_driver);
}

module_init(myinit);
module_exit(myexit);
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#ring0 */

#include <linux/module.h>
#include <linux/kernel.h>

#include "ring0.h"

static int myinit(void)
{
#if defined(__x86_64__) || defined(__i386__)
	Ring0Regs ring0_regs;
	ring0_get_control_regs(&ring0_regs);
	pr_info("cr0 = 0x%8.8llX\n", (unsigned long long)ring0_regs.cr0);
	pr_info("cr2 = 0x%8.8llX\n", (unsigned long long)ring0_regs.cr2);
	pr_info("cr3 = 0x%8.8llX\n", (unsigned long long)ring0_regs.cr3);
#endif
    return 0;
}

static void myexit(void) {}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
#if defined(__x86_64__) || defined(__i386__)

#ifdef THIS_MODULE
#include <linux/kernel.h>
#if defined(__x86_64__)
typedef u64 T;
#elif defined(__i386__)
typedef u32 T;
#endif
#else
#include <stdint.h>
#if defined(__x86_64__)
typedef uint64_t T;
#elif defined(__i386__)
typedef uint32_t T;
#endif
#endif

typedef struct {
    T cr0;
    T cr2;
    T cr3;
} Ring0Regs;

void ring0_get_control_regs(Ring0Regs *ring0_regs)
{
#if defined(__x86_64__)
    __asm__ __volatile__ (
        "mov %%cr0, %%rax;"
        "mov %%eax, %0;"
        "mov %%cr2, %%rax;"
        "mov %%eax, %1;"
        "mov %%cr3, %%rax;"
        "mov %%eax, %2;"
        : "=m" (ring0_regs->cr0),
          "=m" (ring0_regs->cr2),
          "=m" (ring0_regs->cr3)
        :
        : "%rax"
    );
#elif defined(__i386__)
    __asm__ __volatile__ (
        "mov %%cr0, %%eax;"
        "mov %%eax, %0;"
        "mov %%cr2, %%eax;"
        "mov %%eax, %1;"
        "mov %%cr3, %%eax;"
        "mov %%eax, %2;"
        : "=m" (ring0_regs->cr0),
          "=m" (ring0_regs->cr2),
          "=m" (ring0_regs->cr3)
        :
        : "%eax"
    );
#endif
}

#endif


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#schedule */

#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <uapi/linux/stat.h> /* S_IRUSR | S_IWUSR */

static int do_schedule = 1;
module_param_named(schedule, do_schedule, int,  S_IRUSR | S_IWUSR);

static struct task_struct *kthread;

static int work_func(void *data)
{
	unsigned int i = 0;
	while (!kthread_should_stop()) {
		pr_info("%u\n", i);
		i++;
		if (do_schedule)
			schedule();
	}
	return 0;
}

static int myinit(void)
{
	kthread = kthread_create(work_func, NULL, "mykthread");
	wake_up_process(kthread);
	return 0;
}

static void myexit(void)
{
	kthread_stop(kthread);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#seq_file */

#include <linux/debugfs.h>
#include <linux/errno.h> /* EFAULT */
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/printk.h> /* pr_info */
#include <linux/seq_file.h> /* seq_read, seq_lseek, single_release */
#include <linux/slab.h> /* kmalloc, kfree */
#include <linux/uaccess.h> /* copy_from_user, copy_to_user */
#include <uapi/linux/stat.h> /* S_IRUSR */

static int max = 2;
module_param(max, int, S_IRUSR | S_IWUSR);

static struct dentry *debugfs_file;

/* Called at the beginning of every read.
 *
 * The return value is passsed to the first show.
 * It normally represents the current position of the iterator.
 * It could be any struct, but we use just a single integer here.
 *
 * NULL return means stop should be called next, and so the read will be empty..
 * This happens for example for an ftell that goes beyond the file size.
 */
static void *start(struct seq_file *s, loff_t *pos)
{
	loff_t *spos;

	pr_info("start pos = %llx\n", (unsigned long long)*pos);
 	spos = kmalloc(sizeof(loff_t), GFP_KERNEL);
	if (!spos || *pos >= max)
		return NULL;
	*spos = *pos;
	return spos;
}

/* The return value is passed to next show.
 * If NULL, stop is called next instead of show, and read ends.
 *
 * Can get called multiple times, until enough data is returned for the read.
 */
static void *next(struct seq_file *s, void *v, loff_t *pos)
{
	loff_t *spos;

	spos = v;
	pr_info("next pos = %llx\n", (unsigned long long)*pos);
	if (*pos >= max)
		return NULL;
	*pos = ++*spos;
	return spos;
}

/* Called at the end of every read. */
static void stop(struct seq_file *s, void *v)
{
	pr_info("stop\n");
	kfree(v);
}

/* Return 0 means success, SEQ_SKIP ignores previous prints, negative for error. */
static int show(struct seq_file *s, void *v)
{
	loff_t *spos;

	spos = v;
	pr_info("show pos = %llx\n", (unsigned long long)*spos);
	seq_printf(s, "%llx\n", (long long unsigned)*spos);
	return 0;
}

static struct seq_operations my_seq_ops = {
    .next  = next,
    .show  = show,
    .start = start,
    .stop  = stop,
};

static int open(struct inode *inode, struct file *file)
{
	pr_info("open\n");
    return seq_open(file, &my_seq_ops);
}

static struct file_operations fops = {
    .owner   = THIS_MODULE,
    .llseek  = seq_lseek,
    .open    = open,
    .read    = seq_read,
    .release = seq_release
};

static int myinit(void)
{
	debugfs_file = debugfs_create_file(
		"lkmc_seq_file", S_IRUSR, NULL, NULL, &fops);
	if (debugfs_file) {
		return 0;
	} else {
		return -EINVAL;
	}
}

static void myexit(void)
{
	debugfs_remove(debugfs_file);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#seq_file-single_open */

#include <linux/debugfs.h>
#include <linux/errno.h> /* EFAULT */
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/printk.h> /* pr_info */
#include <linux/seq_file.h> /* seq_read, seq_lseek, single_release */
#include <linux/uaccess.h> /* copy_from_user, copy_to_user */
#include <uapi/linux/stat.h> /* S_IRUSR */

static struct dentry *debugfs_file;

static int show(struct seq_file *m, void *v)
{
	seq_printf(m, "ab\ncd\n");
	return 0;
}

static int open(struct inode *inode, struct file *file)
{
	return single_open(file, show, NULL);
}

static const struct file_operations fops = {
	.llseek = seq_lseek,
	.open = open,
	.owner = THIS_MODULE,
	.read = seq_read,
	.release = single_release,
};

static int myinit(void)
{
	debugfs_file = debugfs_create_file("lkmc_seq_file_single_open", S_IRUSR, NULL, NULL, &fops);
	return 0;
}

static void myexit(void)
{
	debugfs_remove(debugfs_file);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#sleep */

#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h> /* atomic_t */

static u32 n = 5;
module_param(n, int, S_IRUSR | S_IWUSR);

static int myinit(void)
{
	u32 i;
	for (i = 0; i < n; ++i) {
		pr_info("%d\n", i);
		usleep_range(1000000, 1000001);
	}
	return 0;
}

static void myexit(void) {}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#config_fortify_source */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>

static int myinit(void)
{
	/* Missing terminaing NUL '\0'. */
	char buf[] = {'p', 'w', 'n'};
	pr_info("%llu\n", (long long unsigned)strlen(buf));
	return 0;
}

static void myexit(void) {}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#sysfs */

#include <linux/init.h>
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <uapi/linux/stat.h> /* S_IRUSR, S_IWUSR  */

enum { FOO_SIZE_MAX = 4 };
static int foo_size;
static char foo_tmp[FOO_SIZE_MAX];

static ssize_t foo_show(struct kobject *kobj, struct kobj_attribute *attr,
		char *buff)
{
	strncpy(buff, foo_tmp, foo_size);
	return foo_size;
}

static ssize_t foo_store(struct  kobject *kobj, struct kobj_attribute *attr,
		const char *buff, size_t count)
{
	foo_size = min(count, (size_t)FOO_SIZE_MAX);
	strncpy(foo_tmp, buff, foo_size);
	return count;
}

static struct kobj_attribute foo_attribute =
	__ATTR(foo, S_IRUGO | S_IWUSR, foo_show, foo_store);

static struct attribute *attrs[] = {
	&foo_attribute.attr,
	NULL,
};

static struct attribute_group attr_group = {
	.attrs = attrs,
};

static struct kobject *kobj;

static int myinit(void)
{
	int ret;

	kobj = kobject_create_and_add("lkmc_sysfs", kernel_kobj);
	if (!kobj)
		return -ENOMEM;
	ret = sysfs_create_group(kobj, &attr_group);
	if (ret)
		kobject_put(kobj);
	return ret;
}

static void myexit(void)
{
	kobject_put(kobj);
}

module_init(myinit);
module_exit(myexit);
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#timers */

#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timer.h>

static int i;
/* We would normally mark this as static and give it a more generic name.
 * But let's do it like this this time for the sake of our GDB kernel module step debugging example. */
void lkmc_timer_callback(struct timer_list *data);
static unsigned long onesec;

DEFINE_TIMER(mytimer, lkmc_timer_callback);

void lkmc_timer_callback(struct timer_list *data)
{
	pr_info("%d\n", i);
	i++;
	if (i == 10)
		i = 0;
	mod_timer(&mytimer, jiffies + onesec);
}

static int myinit(void)
{
	onesec = msecs_to_jiffies(1000);
	mod_timer(&mytimer, jiffies + onesec);
	return 0;
}

static void myexit(void)
{
	del_timer(&mytimer);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
.PHONY: all clean

CFLAGS_EXTRA = -fopenmp -std=c99
CXXFLAGS_EXTRA = -std=c++17
CCFLAGS_EXTRA = -Wall -Werror -Wextra
IN_EXT_C = .c
IN_EXT_CXX = .cpp
LIBS =
OUT_EXT = .out

OUTS := $(foreach IN_EXT,$(IN_EXT_C) $(IN_EXT_CXX),$(addsuffix $(OUT_EXT), $(basename $(wildcard *$(IN_EXT)))))
ifeq ($(BR2_PACKAGE_EIGEN),y)
	CXXFLAGS_EXTRA += -I$(STAGING_DIR)/usr/include/eigen3
	# TODO: was failing with:
	# fatal error: Eigen/Dense: No such file or directory as of
	# 975ce0723ee3fa1fea1766e6683e2f3acb8558d6
	# http://lists.busybox.net/pipermail/buildroot/2018-June/222914.html
	#CXXFLAGS_EXTRA += $(shell $(PKG_CONFIG) --cflags eigen3)
else
	OUTS := $(filter-out eigen_%$(OUT_EXT),$(OUTS))
endif
ifeq ($(BR2_PACKAGE_LIBDRM),y)
	LIBS += $(shell $(PKG_CONFIG) --libs libdrm)
	CFLAGS_EXTRA += $(shell $(PKG_CONFIG) --cflags libdrm)
else
	OUTS := $(filter-out libdrm_%$(OUT_EXT),$(OUTS))
endif
ifeq ($(BR2_PACKAGE_OPENBLAS),y)
	LIBS += -lopenblas
else
	OUTS := $(filter-out openblas$(OUT_EXT),$(OUTS))
endif

all: $(OUTS)

%$(OUT_EXT): %$(IN_EXT_C)
	$(CC) $(CFLAGS) $(CFLAGS_EXTRA) -o '$@' '$<' $(LIBS)

%$(OUT_EXT): %$(IN_EXT_CXX)
	$(CXX) $(CXXFLAGS) $(CXXFLAGS_EXTRA) -o '$@' '$<' $(LIBS)

clean:
	rm -f *'$(OUT_EXT)'


code:
https://github.com/cirosantilli/linux-kernel-module-cheat#rootfs_overlay

. link:sched_getaffinity.c[]


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#anonymous-inode */

#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h> /* sleep */

#include "../anonymous_inode.h"

int main(int argc, char **argv)
{
	char buf[1024];
	int fd_ioctl, fd_ioctl_anon, ret;
	size_t i, nreads;

	if (argc < 2) {
		puts("Usage: ./prog <ioctl-file> [<nreads>]");
		return EXIT_FAILURE;
	} else if (argc > 2) {
		nreads = strtol(argv[2], NULL, 10);
	} else {
		nreads = 3;
	}
	fd_ioctl = open(argv[1], O_RDONLY);
	if (fd_ioctl == -1) {
		perror("open");
		return EXIT_FAILURE;
	}
	ret = ioctl(fd_ioctl, LKMC_ANONYMOUS_INODE_GET_FD, &fd_ioctl_anon);
	if (ret == -1) {
		perror("ioctl");
		return EXIT_FAILURE;
	}
	for (i = 0; i < nreads; ++i) {
		ret = read(fd_ioctl_anon, buf, sizeof(buf));
		printf("%.*s\n", ret, buf);
	}
	close(fd_ioctl_anon);
	close(fd_ioctl);
	return EXIT_SUCCESS;
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#bst-vs-heap */

#include <algorithm>
#include <iostream>
#include <queue>
#include <random>
#include <set>

#include "m5ops.h"

int main(int argc, char **argv) {
    typedef uint64_t I;
    std::vector<I> randoms;
    size_t i, n;
    std::priority_queue<I> heap;
    std::set<I> bst;
    unsigned int seed = std::random_device()();

    // CLI arguments.
    if (argc > 1) {
        n = std::stoi(argv[1]);
    } else {
        n = 1000;
    }

    // Action.
    for (i = 0; i < n; ++i) {
        randoms.push_back(i);
    }
    std::shuffle(randoms.begin(), randoms.end(), std::mt19937(seed));
    for (i = 0; i < n; ++i) {
    	auto random = randoms[i];

        // Heap.
		m5_resetstats();
		heap.emplace(random);
		m5_dumpstats();

        // BST.
		m5_resetstats();
		bst.insert(random);
		m5_dumpstats();
    }
}


code:
#ifndef COMMON_H
#define COMMON_H

#define _XOPEN_SOURCE 700
#include <fcntl.h> /* open */
#include <math.h> /* fabs */
#include <stdint.h> /* uint64_t  */
#include <stdlib.h> /* size_t */
#include <stdio.h> /* snprintf */
#include <sys/types.h>
#include <unistd.h> /* pread, sysconf */
#include <stdbool.h>

/* Format documented at:
 * https://github.com/torvalds/linux/blob/v4.9/Documentation/vm/pagemap.txt
 */
typedef struct {
	uint64_t pfn : 54;
	unsigned int soft_dirty : 1;
	unsigned int file_page : 1;
	unsigned int swapped : 1;
	unsigned int present : 1;
} PagemapEntry;

/* Parse the pagemap entry for the given virtual address.
 *
 * @param[out] entry      the parsed entry
 * @param[in]  pagemap_fd file descriptor to an open /proc/pid/pagemap file
 * @param[in]  vaddr      virtual address to get entry for
 * @return 0 for success, 1 for failure
 */
int pagemap_get_entry(PagemapEntry *entry, int pagemap_fd, uintptr_t vaddr)
{
	size_t nread;
	ssize_t ret;
	uint64_t data;

	nread = 0;
	while (nread < sizeof(data)) {
		ret = pread(
			pagemap_fd,
			&data,
			sizeof(data),
			(vaddr / sysconf(_SC_PAGE_SIZE)) * sizeof(data) + nread
		);
		nread += ret;
		if (ret <= 0) {
			return 1;
		}
	}
	entry->pfn = data & (((uint64_t)1 << 54) - 1);
	entry->soft_dirty = (data >> 54) & 1;
	entry->file_page = (data >> 61) & 1;
	entry->swapped = (data >> 62) & 1;
	entry->present = (data >> 63) & 1;
	return 0;
}

/* Convert the given virtual address to physical using /proc/PID/pagemap.
 *
 * @param[out] paddr physical address
 * @param[in]  pid   process to convert for
 * @param[in] vaddr virtual address to get entry for
 * @return 0 for success, 1 for failure
 */
int virt_to_phys_user(uintptr_t *paddr, pid_t pid, uintptr_t vaddr)
{
	char pagemap_file[BUFSIZ];
	int pagemap_fd;

	snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%ju/pagemap", (uintmax_t)pid);
	pagemap_fd = open(pagemap_file, O_RDONLY);
	if (pagemap_fd < 0) {
		return 1;
	}
	PagemapEntry entry;
	if (pagemap_get_entry(&entry, pagemap_fd, vaddr)) {
		return 1;
	}
	close(pagemap_fd);
	*paddr = (entry.pfn * sysconf(_SC_PAGE_SIZE)) + (vaddr % sysconf(_SC_PAGE_SIZE));
	return 0;
}

bool common_vector_equal(size_t n, double * v1, double * v2, double max_err)
{
	double sum = 0.0;
	double diff;
	size_t i;
	for (i = 0; i < n; ++i) {
		diff = v1[i] - v2[i];
		sum += diff * diff;
	}
	if (sqrt(sum)/n > max_err)
		return false;
	return true;
}

#endif


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#ctrl-alt-del */

#define _XOPEN_SOURCE 700
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/reboot.h>
#include <unistd.h>

void signal_handler(int sig) {
	write(STDOUT_FILENO, "cad\n", 4);
	signal(sig, signal_handler);
}

int main(void) {
	int i = 0;
	/* Disable the forced reboot, enable sending SIGINT to init. */
	reboot(RB_DISABLE_CAD);
    signal(SIGINT, signal_handler);
	while (1) {
		sleep(1);
		printf("%d\n", i);
		i++;
	}
    return EXIT_SUCCESS;
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#eigen
 * Adapted from: https://eigen.tuxfamily.org/dox/GettingStarted.html
 */
#include <iostream>
#include <Eigen/Dense>
int main() {
	Eigen::MatrixXd m(2,2);
	m(0,0) = 3;
	m(1,0) = 2.5;
	m(0,1) = -1;
	m(1,1) = m(1,0) + m(0,1);
	std::cout << m << std::endl;
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#sanity-checks */

#include <stdio.h>
#include <stdlib.h>

int main(void) {
	puts("hello");
	return EXIT_SUCCESS;
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#sanity-checks */

#include <iostream>

int main() {
    std::cout << "hello cpp" << std::endl;
}


code:
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <sys/reboot.h>
#include <unistd.h>

int main(int argc, char **argv)
{
	int i;

	puts("args:");
	for (i = 0; i < argc; ++i)
		puts(argv[i]);
	puts("");

	puts("env:");
	extern char **environ;
	char **env = environ;
	while (*env) {
		printf("%s\n", *env);
		env++;
	}
	puts("");

	/* Poweroff. */
	reboot(RB_POWER_OFF);
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#ioctl */

#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include "../ioctl.h"

int main(int argc, char **argv)
{
	char *ioctl_path;
	int fd, request, arg0, arg1, arg_int, ret;
	lkmc_ioctl_struct arg_struct;

	if (argc < 2) {
		puts("Usage: ./prog <ioctl-file> <request> [<arg>...]");
		return EXIT_FAILURE;
	}
	ioctl_path = argv[1];
	request = strtol(argv[2], NULL, 10);
	if (argc > 3) {
		arg0 = strtol(argv[3], NULL, 10);
	}
	if (argc > 4) {
		arg1 = strtol(argv[4], NULL, 10);
	}

	fd = open(ioctl_path, O_RDONLY);
	if (fd == -1) {
		perror("open");
		return EXIT_FAILURE;
	}
	switch (request)
	{
		case 0:
			arg_int = arg0;
			ret = ioctl(fd, LKMC_IOCTL_INC, &arg_int);
			if (ret != -1) {
				printf("%d\n", arg_int);
			}
			break;
		case 1:
			arg_struct.i = arg0;
			arg_struct.j = arg1;
			ret = ioctl(fd, LKMC_IOCTL_INC_DEC, &arg_struct);
			if (ret != -1) {
				printf("%d %d\n", arg_struct.i, arg_struct.j);
			}
			break;
		default:
			puts("error: unknown request");
			return EXIT_FAILURE;
	}
	if (ret == -1) {
		perror("ioctl");
		printf("errno = %d\n", errno);
		return EXIT_FAILURE;
	}
	close(fd);
	return EXIT_SUCCESS;
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#drm
 * Adapted from: https://github.com/dvdhrm/docs/blob/fad7c3203b14e67053e0fc41d8490138b8ff47dd/drm-howto/modeset.c */

/*
 * modeset - DRM Modesetting Example
 *
 * Written 2012 by David Herrmann <dh.herrmann@googlemail.com>
 * Dedicated to the Public Domain.
 */

/*
 * DRM Modesetting Howto
 * This document describes the DRM modesetting API. Before we can use the DRM
 * API, we have to include xf86drm.h and xf86drmMode.h. Both are provided by
 * libdrm which every major distribution ships by default. It has no other
 * dependencies and is pretty small.
 *
 * Please ignore all forward-declarations of functions which are used later. I
 * reordered the functions so you can read this document from top to bottom. If
 * you reimplement it, you would probably reorder the functions to avoid all the
 * nasty forward declarations.
 *
 * For easier reading, we ignore all memory-allocation errors of malloc() and
 * friends here. However, we try to correctly handle all other kinds of errors
 * that may occur.
 *
 * All functions and global variables are prefixed with "modeset_*" in this
 * file. So it should be clear whether a function is a local helper or if it is
 * provided by some external library.
 */

#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>

struct modeset_dev;
static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn,
			     struct modeset_dev *dev);
static int modeset_create_fb(int fd, struct modeset_dev *dev);
static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn,
			     struct modeset_dev *dev);
static int modeset_open(int *out, const char *node);
static int modeset_prepare(int fd);
static void modeset_draw(void);
static void modeset_cleanup(int fd);

/*
 * When the linux kernel detects a graphics-card on your machine, it loads the
 * correct device driver (located in kernel-tree at ./drivers/gpu/drm/<xy>) and
 * provides two character-devices to control it. Udev (or whatever hotplugging
 * application you use) will create them as:
 *     /dev/dri/card0
 *     /dev/dri/controlID64
 * We only need the first one. You can hard-code this path into your application
 * like we do here, but it is recommended to use libudev with real hotplugging
 * and multi-seat support. However, this is beyond the scope of this document.
 * Also note that if you have multiple graphics-cards, there may also be
 * /dev/dri/card1, /dev/dri/card2, ...
 *
 * We simply use /dev/dri/card0 here but the user can specify another path on
 * the command line.
 *
 * modeset_open(out, node): This small helper function opens the DRM device
 * which is given as @node. The new fd is stored in @out on success. On failure,
 * a negative error code is returned.
 * After opening the file, we also check for the DRM_CAP_DUMB_BUFFER capability.
 * If the driver supports this capability, we can create simple memory-mapped
 * buffers without any driver-dependent code. As we want to avoid any radeon,
 * nvidia, intel, etc. specific code, we depend on DUMB_BUFFERs here.
 */

static int modeset_open(int *out, const char *node)
{
	int fd, ret;
	uint64_t has_dumb;

	fd = open(node, O_RDWR | O_CLOEXEC);
	if (fd < 0) {
		ret = -errno;
		fprintf(stderr, "cannot open '%s': %m\n", node);
		return ret;
	}

	if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 ||
	    !has_dumb) {
		fprintf(stderr, "drm device '%s' does not support dumb buffers\n",
			node);
		close(fd);
		return -EOPNOTSUPP;
	}

	*out = fd;
	return 0;
}

/*
 * As a next step we need to find our available display devices. libdrm provides
 * a drmModeRes structure that contains all the needed information. We can
 * retrieve it via drmModeGetResources(fd) and free it via
 * drmModeFreeResources(res) again.
 *
 * A physical connector on your graphics card is called a "connector". You can
 * plug a monitor into it and control what is displayed. We are definitely
 * interested in what connectors are currently used, so we simply iterate
 * through the list of connectors and try to display a test-picture on each
 * available monitor.
 * However, this isn't as easy as it sounds. First, we need to check whether the
 * connector is actually used (a monitor is plugged in and turned on). Then we
 * need to find a CRTC that can control this connector. CRTCs are described
 * later on. After that we create a framebuffer object. If we have all this, we
 * can mmap() the framebuffer and draw a test-picture into it. Then we can tell
 * the DRM device to show the framebuffer on the given CRTC with the selected
 * connector.
 *
 * As we want to draw moving pictures on the framebuffer, we actually have to
 * remember all these settings. Therefore, we create one "struct modeset_dev"
 * object for each connector+crtc+framebuffer pair that we successfully
 * initialized and push it into the global device-list.
 *
 * Each field of this structure is described when it is first used. But as a
 * summary:
 * "struct modeset_dev" contains: {
 *  - @next: points to the next device in the single-linked list
 *
 *  - @width: width of our buffer object
 *  - @height: height of our buffer object
 *  - @stride: stride value of our buffer object
 *  - @size: size of the memory mapped buffer
 *  - @handle: a DRM handle to the buffer object that we can draw into
 *  - @map: pointer to the memory mapped buffer
 *
 *  - @mode: the display mode that we want to use
 *  - @fb: a framebuffer handle with our buffer object as scanout buffer
 *  - @conn: the connector ID that we want to use with this buffer
 *  - @crtc: the crtc ID that we want to use with this connector
 *  - @saved_crtc: the configuration of the crtc before we changed it. We use it
 *                 so we can restore the same mode when we exit.
 * }
 */

struct modeset_dev {
	struct modeset_dev *next;

	uint32_t width;
	uint32_t height;
	uint32_t stride;
	uint32_t size;
	uint32_t handle;
	uint8_t *map;

	drmModeModeInfo mode;
	uint32_t fb;
	uint32_t conn;
	uint32_t crtc;
	drmModeCrtc *saved_crtc;
};

static struct modeset_dev *modeset_list = NULL;

/*
 * So as next step we need to actually prepare all connectors that we find. We
 * do this in this little helper function:
 *
 * modeset_prepare(fd): This helper function takes the DRM fd as argument and
 * then simply retrieves the resource-info from the device. It then iterates
 * through all connectors and calls other helper functions to initialize this
 * connector (described later on).
 * If the initialization was successful, we simply add this object as new device
 * into the global modeset device list.
 *
 * The resource-structure contains a list of all connector-IDs. We use the
 * helper function drmModeGetConnector() to retrieve more information on each
 * connector. After we are done with it, we free it again with
 * drmModeFreeConnector().
 * Our helper modeset_setup_dev() returns -ENOENT if the connector is currently
 * unused and no monitor is plugged in. So we can ignore this connector.
 */

static int modeset_prepare(int fd)
{
	drmModeRes *res;
	drmModeConnector *conn;
	unsigned int i;
	struct modeset_dev *dev;
	int ret;

	/* retrieve resources */
	res = drmModeGetResources(fd);
	if (!res) {
		fprintf(stderr, "cannot retrieve DRM resources (%d): %m\n",
			errno);
		return -errno;
	}

	/* iterate all connectors */
	for (i = 0; i < (unsigned int)res->count_connectors; ++i) {
		/* get information for each connector */
		conn = drmModeGetConnector(fd, res->connectors[i]);
		if (!conn) {
			fprintf(stderr, "cannot retrieve DRM connector %u:%u (%d): %m\n",
				i, res->connectors[i], errno);
			continue;
		}

		/* create a device structure */
		dev = malloc(sizeof(*dev));
		memset(dev, 0, sizeof(*dev));
		dev->conn = conn->connector_id;

		/* call helper function to prepare this connector */
		ret = modeset_setup_dev(fd, res, conn, dev);
		if (ret) {
			if (ret != -ENOENT) {
				errno = -ret;
				fprintf(stderr, "cannot setup device for connector %u:%u (%d): %m\n",
					i, res->connectors[i], errno);
			}
			free(dev);
			drmModeFreeConnector(conn);
			continue;
		}

		/* free connector data and link device into global list */
		drmModeFreeConnector(conn);
		dev->next = modeset_list;
		modeset_list = dev;
	}

	/* free resources again */
	drmModeFreeResources(res);
	return 0;
}

/*
 * Now we dig deeper into setting up a single connector. As described earlier,
 * we need to check several things first:
 *   * If the connector is currently unused, that is, no monitor is plugged in,
 *     then we can ignore it.
 *   * We have to find a suitable resolution and refresh-rate. All this is
 *     available in drmModeModeInfo structures saved for each crtc. We simply
 *     use the first mode that is available. This is always the mode with the
 *     highest resolution.
 *     A more sophisticated mode-selection should be done in real applications,
 *     though.
 *   * Then we need to find an CRTC that can drive this connector. A CRTC is an
 *     internal resource of each graphics-card. The number of CRTCs controls how
 *     many connectors can be controlled indepedently. That is, a graphics-cards
 *     may have more connectors than CRTCs, which means, not all monitors can be
 *     controlled independently.
 *     There is actually the possibility to control multiple connectors via a
 *     single CRTC if the monitors should display the same content. However, we
 *     do not make use of this here.
 *     So think of connectors as pipelines to the connected monitors and the
 *     CRTCs are the controllers that manage which data goes to which pipeline.
 *     If there are more pipelines than CRTCs, then we cannot control all of
 *     them at the same time.
 *   * We need to create a framebuffer for this connector. A framebuffer is a
 *     memory buffer that we can write XRGB32 data into. So we use this to
 *     render our graphics and then the CRTC can scan-out this data from the
 *     framebuffer onto the monitor.
 */

static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn,
			     struct modeset_dev *dev)
{
	int ret;

	/* check if a monitor is connected */
	if (conn->connection != DRM_MODE_CONNECTED) {
		fprintf(stderr, "ignoring unused connector %u\n",
			conn->connector_id);
		return -ENOENT;
	}

	/* check if there is at least one valid mode */
	if (conn->count_modes == 0) {
		fprintf(stderr, "no valid mode for connector %u\n",
			conn->connector_id);
		return -EFAULT;
	}

	/* copy the mode information into our device structure */
	memcpy(&dev->mode, &conn->modes[0], sizeof(dev->mode));
	dev->width = conn->modes[0].hdisplay;
	dev->height = conn->modes[0].vdisplay;
	fprintf(stderr, "mode for connector %u is %ux%u\n",
		conn->connector_id, dev->width, dev->height);

	/* find a crtc for this connector */
	ret = modeset_find_crtc(fd, res, conn, dev);
	if (ret) {
		fprintf(stderr, "no valid crtc for connector %u\n",
			conn->connector_id);
		return ret;
	}

	/* create a framebuffer for this CRTC */
	ret = modeset_create_fb(fd, dev);
	if (ret) {
		fprintf(stderr, "cannot create framebuffer for connector %u\n",
			conn->connector_id);
		return ret;
	}

	return 0;
}

/*
 * modeset_find_crtc(fd, res, conn, dev): This small helper tries to find a
 * suitable CRTC for the given connector. We have actually have to introduce one
 * more DRM object to make this more clear: Encoders.
 * Encoders help the CRTC to convert data from a framebuffer into the right
 * format that can be used for the chosen connector. We do not have to
 * understand any more of these conversions to make use of it. However, you must
 * know that each connector has a limited list of encoders that it can use. And
 * each encoder can only work with a limited list of CRTCs. So what we do is
 * trying each encoder that is available and looking for a CRTC that this
 * encoder can work with. If we find the first working combination, we are happy
 * and write it into the @dev structure.
 * But before iterating all available encoders, we first try the currently
 * active encoder+crtc on a connector to avoid a full modeset.
 *
 * However, before we can use a CRTC we must make sure that no other device,
 * that we setup previously, is already using this CRTC. Remember, we can only
 * drive one connector per CRTC! So we simply iterate through the "modeset_list"
 * of previously setup devices and check that this CRTC wasn't used before.
 * Otherwise, we continue with the next CRTC/Encoder combination.
 */

static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn,
			     struct modeset_dev *dev)
{
	drmModeEncoder *enc;
	unsigned int i, j;
	int32_t crtc;
	struct modeset_dev *iter;

	/* first try the currently conected encoder+crtc */
	if (conn->encoder_id)
		enc = drmModeGetEncoder(fd, conn->encoder_id);
	else
		enc = NULL;

	if (enc) {
		if (enc->crtc_id) {
			crtc = enc->crtc_id;
			for (iter = modeset_list; iter; iter = iter->next) {
				if ((int32_t)iter->crtc == crtc) {
					crtc = -1;
					break;
				}
			}

			if (crtc >= 0) {
				drmModeFreeEncoder(enc);
				dev->crtc = crtc;
				return 0;
			}
		}

		drmModeFreeEncoder(enc);
	}

	/* If the connector is not currently bound to an encoder or if the
	 * encoder+crtc is already used by another connector (actually unlikely
	 * but lets be safe), iterate all other available encoders to find a
	 * matching CRTC. */
	for (i = 0; i < (unsigned int)conn->count_encoders; ++i) {
		enc = drmModeGetEncoder(fd, conn->encoders[i]);
		if (!enc) {
			fprintf(stderr, "cannot retrieve encoder %u:%u (%d): %m\n",
				i, conn->encoders[i], errno);
			continue;
		}

		/* iterate all global CRTCs */
		for (j = 0; j < (unsigned int)res->count_crtcs; ++j) {
			/* check whether this CRTC works with the encoder */
			if (!(enc->possible_crtcs & (1 << j)))
				continue;

			/* check that no other device already uses this CRTC */
			crtc = res->crtcs[j];
			for (iter = modeset_list; iter; iter = iter->next) {
				if ((int32_t)iter->crtc == crtc) {
					crtc = -1;
					break;
				}
			}

			/* we have found a CRTC, so save it and return */
			if (crtc >= 0) {
				drmModeFreeEncoder(enc);
				dev->crtc = crtc;
				return 0;
			}
		}

		drmModeFreeEncoder(enc);
	}

	fprintf(stderr, "cannot find suitable CRTC for connector %u\n",
		conn->connector_id);
	return -ENOENT;
}

/*
 * modeset_create_fb(fd, dev): After we have found a crtc+connector+mode
 * combination, we need to actually create a suitable framebuffer that we can
 * use with it. There are actually two ways to do that:
 *   * We can create a so called "dumb buffer". This is a buffer that we can
 *     memory-map via mmap() and every driver supports this. We can use it for
 *     unaccelerated software rendering on the CPU.
 *   * We can use libgbm to create buffers available for hardware-acceleration.
 *     libgbm is an abstraction layer that creates these buffers for each
 *     available DRM driver. As there is no generic API for this, each driver
 *     provides its own way to create these buffers.
 *     We can then use such buffers to create OpenGL contexts with the mesa3D
 *     library.
 * We use the first solution here as it is much simpler and doesn't require any
 * external libraries. However, if you want to use hardware-acceleration via
 * OpenGL, it is actually pretty easy to create such buffers with libgbm and
 * libEGL. But this is beyond the scope of this document.
 *
 * So what we do is requesting a new dumb-buffer from the driver. We specify the
 * same size as the current mode that we selected for the connector.
 * Then we request the driver to prepare this buffer for memory mapping. After
 * that we perform the actual mmap() call. So we can now access the framebuffer
 * memory directly via the dev->map memory map.
 */

static int modeset_create_fb(int fd, struct modeset_dev *dev)
{
	struct drm_mode_create_dumb creq;
	struct drm_mode_destroy_dumb dreq;
	struct drm_mode_map_dumb mreq;
	int ret;

	/* create dumb buffer */
	memset(&creq, 0, sizeof(creq));
	creq.width = dev->width;
	creq.height = dev->height;
	creq.bpp = 32;
	ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
	if (ret < 0) {
		fprintf(stderr, "cannot create dumb buffer (%d): %m\n",
			errno);
		return -errno;
	}
	dev->stride = creq.pitch;
	dev->size = creq.size;
	dev->handle = creq.handle;

	/* create framebuffer object for the dumb-buffer */
	ret = drmModeAddFB(fd, dev->width, dev->height, 24, 32, dev->stride,
			   dev->handle, &dev->fb);
	if (ret) {
		fprintf(stderr, "cannot create framebuffer (%d): %m\n",
			errno);
		ret = -errno;
		goto err_destroy;
	}

	/* prepare buffer for memory mapping */
	memset(&mreq, 0, sizeof(mreq));
	mreq.handle = dev->handle;
	ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
	if (ret) {
		fprintf(stderr, "cannot map dumb buffer (%d): %m\n",
			errno);
		ret = -errno;
		goto err_fb;
	}

	/* perform actual memory mapping */
	dev->map = mmap(0, dev->size, PROT_READ | PROT_WRITE, MAP_SHARED,
		        fd, mreq.offset);
	if (dev->map == MAP_FAILED) {
		fprintf(stderr, "cannot mmap dumb buffer (%d): %m\n",
			errno);
		ret = -errno;
		goto err_fb;
	}

	/* clear the framebuffer to 0 */
	memset(dev->map, 0, dev->size);

	return 0;

err_fb:
	drmModeRmFB(fd, dev->fb);
err_destroy:
	memset(&dreq, 0, sizeof(dreq));
	dreq.handle = dev->handle;
	drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
	return ret;
}

/*
 * Finally! We have a connector with a suitable CRTC. We know which mode we want
 * to use and we have a framebuffer of the correct size that we can write to.
 * There is nothing special left to do. We only have to program the CRTC to
 * connect each new framebuffer to each selected connector for each combination
 * that we saved in the global modeset_list.
 * This is done with a call to drmModeSetCrtc().
 *
 * So we are ready for our main() function. First we check whether the user
 * specified a DRM device on the command line, otherwise we use the default
 * /dev/dri/card0. Then we open the device via modeset_open(). modeset_prepare()
 * prepares all connectors and we can loop over "modeset_list" and call
 * drmModeSetCrtc() on every CRTC/connector combination.
 *
 * But printing empty black pages is boring so we have another helper function
 * modeset_draw() that draws some colors into the framebuffer for 5 seconds and
 * then returns. And then we have all the cleanup functions which correctly free
 * all devices again after we used them. All these functions are described below
 * the main() function.
 *
 * As a side note: drmModeSetCrtc() actually takes a list of connectors that we
 * want to control with this CRTC. We pass only one connector, though. As
 * explained earlier, if we used multiple connectors, then all connectors would
 * have the same controlling framebuffer so the output would be cloned. This is
 * most often not what you want so we avoid explaining this feature here.
 * Furthermore, all connectors will have to run with the same mode, which is
 * also often not guaranteed. So instead, we only use one connector per CRTC.
 *
 * Before calling drmModeSetCrtc() we also save the current CRTC configuration.
 * This is used in modeset_cleanup() to restore the CRTC to the same mode as was
 * before we changed it.
 * If we don't do this, the screen will stay blank after we exit until another
 * application performs modesetting itself.
 */

int main(int argc, char **argv)
{
	int ret, fd;
	const char *card;
	struct modeset_dev *iter;

	/* check which DRM device to open */
	if (argc > 1)
		card = argv[1];
	else
		card = "/dev/dri/card0";

	fprintf(stderr, "using card '%s'\n", card);

	/* open the DRM device */
	ret = modeset_open(&fd, card);
	if (ret)
		goto out_return;

	/* prepare all connectors and CRTCs */
	ret = modeset_prepare(fd);
	if (ret)
		goto out_close;

	/* perform actual modesetting on each found connector+CRTC */
	for (iter = modeset_list; iter; iter = iter->next) {
		iter->saved_crtc = drmModeGetCrtc(fd, iter->crtc);
		ret = drmModeSetCrtc(fd, iter->crtc, iter->fb, 0, 0,
				     &iter->conn, 1, &iter->mode);
		if (ret)
			fprintf(stderr, "cannot set CRTC for connector %u (%d): %m\n",
				iter->conn, errno);
	}

	/* draw some colors for 5seconds */
	modeset_draw();

	/* cleanup everything */
	modeset_cleanup(fd);

	ret = 0;

out_close:
	close(fd);
out_return:
	if (ret) {
		errno = -ret;
		fprintf(stderr, "modeset failed with error %d: %m\n", errno);
	} else {
		fprintf(stderr, "exiting\n");
	}
	return ret;
}

/*
 * A short helper function to compute a changing color value. No need to
 * understand it.
 */

static uint8_t next_color(bool *up, uint8_t cur, unsigned int mod)
{
	uint8_t next;

	next = cur + (*up ? 1 : -1) * (rand() % mod);
	if ((*up && next < cur) || (!*up && next > cur)) {
		*up = !*up;
		next = cur;
	}

	return next;
}

/*
 * modeset_draw(): This draws a solid color into all configured framebuffers.
 * Every 100ms the color changes to a slightly different color so we get some
 * kind of smoothly changing color-gradient.
 *
 * The color calculation can be ignored as it is pretty boring. So the
 * interesting stuff is iterating over "modeset_list" and then through all lines
 * and width. We then set each pixel individually to the current color.
 *
 * We do this 50 times as we sleep 100ms after each redraw round. This makes
 * 50*100ms = 5000ms = 5s so it takes about 5seconds to finish this loop.
 *
 * Please note that we draw directly into the framebuffer. This means that you
 * will see flickering as the monitor might refresh while we redraw the screen.
 * To avoid this you would need to use two framebuffers and a call to
 * drmModeSetCrtc() to switch between both buffers.
 * You can also use drmModePageFlip() to do a vsync'ed pageflip. But this is
 * beyond the scope of this document.
 */

static void modeset_draw(void)
{
	uint8_t r, g, b;
	bool r_up, g_up, b_up;
	unsigned int i, j, k, off;
	struct modeset_dev *iter;

	srand(time(NULL));
	r = rand() % 0xff;
	g = rand() % 0xff;
	b = rand() % 0xff;
	r_up = g_up = b_up = true;

	for (i = 0; i < 50; ++i) {
		r = next_color(&r_up, r, 20);
		g = next_color(&g_up, g, 10);
		b = next_color(&b_up, b, 5);

		for (iter = modeset_list; iter; iter = iter->next) {
			for (j = 0; j < iter->height; ++j) {
				for (k = 0; k < iter->width; ++k) {
					off = iter->stride * j + k * 4;
					*(uint32_t*)&iter->map[off] =
						     (r << 16) | (g << 8) | b;
				}
			}
		}

		usleep(100000);
	}
}

/*
 * modeset_cleanup(fd): This cleans up all the devices we created during
 * modeset_prepare(). It resets the CRTCs to their saved states and deallocates
 * all memory.
 * It should be pretty obvious how all of this works.
 */

static void modeset_cleanup(int fd)
{
	struct modeset_dev *iter;
	struct drm_mode_destroy_dumb dreq;

	while (modeset_list) {
		/* remove from global list */
		iter = modeset_list;
		modeset_list = iter->next;

		/* restore saved CRTC configuration */
		drmModeSetCrtc(fd,
			       iter->saved_crtc->crtc_id,
			       iter->saved_crtc->buffer_id,
			       iter->saved_crtc->x,
			       iter->saved_crtc->y,
			       &iter->conn,
			       1,
			       &iter->saved_crtc->mode);
		drmModeFreeCrtc(iter->saved_crtc);

		/* unmap buffer */
		munmap(iter->map, iter->size);

		/* delete framebuffer */
		drmModeRmFB(fd, iter->fb);

		/* delete dumb buffer */
		memset(&dreq, 0, sizeof(dreq));
		dreq.handle = iter->handle;
		drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);

		/* free allocated memory */
		free(iter);
	}
}

/*
 * I hope this was a short but easy overview of the DRM modesetting API. The DRM
 * API offers much more capabilities including:
 *  - double-buffering or tripple-buffering (or whatever you want)
 *  - vsync'ed page-flips
 *  - hardware-accelerated rendering (for example via OpenGL)
 *  - output cloning
 *  - graphics-clients plus authentication
 *  - DRM planes/overlays/sprites
 *  - ...
 * If you are interested in these topics, I can currently only redirect you to
 * existing implementations, including:
 *  - plymouth (which uses dumb-buffers like this example; very easy to understand)
 *  - kmscon (which uses libuterm to do this)
 *  - wayland (very sophisticated DRM renderer; hard to understand fully as it
 *             uses more complicated techniques like DRM planes)
 *  - xserver (very hard to understand as it is split across many files/projects)
 *
 * But understanding how modesetting (as described in this document) works, is
 * essential to understand all further DRM topics.
 *
 * Any feedback is welcome. Feel free to use this code freely for your own
 * documentation or projects.
 *
 *  - Hosted on http://github.com/dvdhrm/docs
 *  - Written by David Herrmann <dh.herrmann@googlemail.com>
 */


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#m5ops-instructions */

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include "m5ops.h"

int main(int argc, char **argv)
{
	char action;
	if (argc > 1) {
		action = argv[1][0];
	} else {
		action = 'e';
	}
	switch (action)
	{
		case 'c':
			m5_checkpoint();
			break;
		case 'd':
			m5_dumpstats();
			break;
		case 'e':
			m5_exit();
			break;
		case 'f':
			m5_fail_1();
			break;
		case 'r':
			m5_resetstats();
			break;
	}
	return EXIT_SUCCESS;
}


code:
#ifndef M5OPS_H
#define M5OPS_H

#if defined(__arm__)
static void m5_checkpoint(void)
{
	__asm__ __volatile__ ("mov r0, #0; mov r1, #0; mov r2, #0; mov r3, #0; .inst 0xEE000110 | (0x43 << 16);");
};
static void m5_dumpstats(void)
{
	__asm__ __volatile__ ("mov r0, #0; mov r1, #0; mov r2, #0; mov r3, #0; .inst 0xEE000110 | (0x41 << 16);");
};
static void m5_exit()
{
	__asm__ __volatile__ ("mov r0, #0; .inst 0xEE000110 | (0x21 << 16);");
};
static void m5_fail_1(void)
{
	__asm__ __volatile__ ("mov r0, #0; mov r1, #0; mov r2, #1; mov r3, #0; .inst 0xEE000110 | (0x22 << 16);");
};
static void m5_resetstats(void)
{
	__asm__ __volatile__ ("mov r0, #0; mov r1, #0; mov r2, #0; mov r3, #0; .inst 0xEE000110 | (0x40 << 16);");
};
#elif defined(__aarch64__)
static void m5_checkpoint(void)
{
	__asm__ __volatile__ ("mov x0, #0; mov x1, #0; .inst 0xFF000110 | (0x43 << 16);");
};
static void m5_dumpstats(void)
{
	__asm__ __volatile__ ("mov x0, #0; mov x1, #0; .inst 0xFF000110 | (0x41 << 16);");
};
static void m5_exit(void)
{
	__asm__ __volatile__ ("mov x0, #0; .inst 0XFF000110 | (0x21 << 16);");
};
static void m5_fail_1(void)
{
	__asm__ __volatile__ ("mov x0, #0; mov x1, #1; .inst 0xFF000110 | (0x22 << 16);");
};
static void m5_resetstats(void)
{
	__asm__ __volatile__ ("mov x0, #0; mov x1, #0; .inst 0XFF000110 | (0x40 << 16);");
};
#else
static void m5_checkpoint(void) {};
static void m5_dumpstats(void) {};
static void m5_exit(void) {};
static void m5_fail_1(void) {};
static void m5_resetstats(void) {};
#endif

#endif


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#mmap */

#define _XOPEN_SOURCE 700
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h> /* uintmax_t */
#include <string.h>
#include <sys/mman.h>
#include <unistd.h> /* sysconf */

#include "common.h" /* virt_to_phys_user */

enum { BUFFER_SIZE = 4 };

int main(int argc, char **argv)
{
	int fd;
	long page_size;
	char *address1, *address2;
	char buf[BUFFER_SIZE];
	uintptr_t paddr;

	if (argc < 2) {
		printf("Usage: %s <mmap_file>\n", argv[0]);
		return EXIT_FAILURE;
	}
	page_size = sysconf(_SC_PAGE_SIZE);
	printf("open pathname = %s\n", argv[1]);
	fd = open(argv[1], O_RDWR | O_SYNC);
	if (fd < 0) {
		perror("open");
		assert(0);
	}
	printf("fd = %d\n", fd);

    /* mmap twice for double fun. */
	puts("mmap 1");
	address1 = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	if (address1 == MAP_FAILED) {
		perror("mmap");
		assert(0);
	}
	puts("mmap 2");
	address2 = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	if (address2 == MAP_FAILED) {
		perror("mmap");
		return EXIT_FAILURE;
	}
	assert(address1 != address2);

    /* Read and modify memory. */
	puts("access 1");
	assert(!strcmp(address1, "asdf"));
	/* vm_fault */
	puts("access 2");
	assert(!strcmp(address2, "asdf"));
	/* vm_fault */
	strcpy(address1, "qwer");
	/* Also modified. So both virtual addresses point to the same physical address. */
	assert(!strcmp(address2, "qwer"));

	/* Check that the physical addresses are the same.
	 * They are, but TODO why virt_to_phys on kernel gives a different value? */
	assert(!virt_to_phys_user(&paddr, getpid(), (uintptr_t)address1));
	printf("paddr1 = 0x%jx\n", (uintmax_t)paddr);
	assert(!virt_to_phys_user(&paddr, getpid(), (uintptr_t)address2));
	printf("paddr2 = 0x%jx\n", (uintmax_t)paddr);

    /* Check that modifications made from userland are also visible from the kernel. */
	read(fd, buf, BUFFER_SIZE);
	assert(!memcmp(buf, "qwer", BUFFER_SIZE));

	/* Modify the data from the kernel, and check that the change is visible from userland. */
	write(fd, "zxcv", 4);
	assert(!strcmp(address1, "zxcv"));
	assert(!strcmp(address2, "zxcv"));

    /* Cleanup. */
    puts("munmap 1");
	if (munmap(address1, page_size)) {
		perror("munmap");
		assert(0);
	}
    puts("munmap 2");
	if (munmap(address2, page_size)) {
		perror("munmap");
		assert(0);
	}
    puts("close");
	close(fd);
	return EXIT_SUCCESS;
}