close

 

kernel 中使用 interrupt 並與 userspace process 之溝通

在 kernel 中接受到 button trigger 的 interrupt 後,透過 signal 與 userspace 的 process 溝通



kernel ————————–userspace

interrupt ———————– signal(SIGUSR1, nvramIrqHandle)

送 signal 給 suerspace —–> 攔截 kernel 丟過來的 signal


實做:

kernel 部分:

p = find_task_by_pid(pid); //pid 為 userspace 的 task pid

send_sig(SIGUSR1,p);// 產生 signal 到 userspace 的 process 去

 

https://github.com/daveti/ksig/blob/master/signal_kernel.c

/*
 * signal_kernel.c
 * A kernel module used to send signals to the user space
 * Originated from http://people.ee.ethz.ch/~arkeller/linux/code/signal_kernel_phil_bergeron_burns.c
 * Modified by daveti
 * Aug 23, 2014
 * root@davejingtian.org
 * http://davejingtian.org
 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/siginfo.h>	//siginfo
#include <linux/rcupdate.h>	//rcu_read_lock
#include <linux/sched.h>	//find_task_by_pid_type
#include <linux/debugfs.h>
#include <linux/uaccess.h>


#define SIG_TEST 44	// we choose 44 as our signal number (real-time signals are in the range of 33 to 64)

struct dentry *file;

static ssize_t write_pid(struct file *file, const char __user *buf,
                                size_t count, loff_t *ppos)
{
	char mybuf[10];
	int pid = 0;
	int ret;
	struct siginfo info;
	struct task_struct *t;
	/* read the value from user space */
	if(count > 10)
		return -EINVAL;
	copy_from_user(mybuf, buf, count);
	sscanf(mybuf, "%d", &pid);
	pr_info("pid = %d\n", pid);

	/* prepare the signal */
	memset(&info, 0, sizeof(struct siginfo));
	info.si_signo = SIG_TEST;
	/*
	this is bit of a trickery: SI_QUEUE is normally used by sigqueue from user space,
	and kernel space should use SI_KERNEL. But if SI_KERNEL is used the real_time data 
	is not delivered to the user space signal handler function. 
	*/
	info.si_code = SI_QUEUE;
	/* real time signals may have 32 bits of data. */
	info.si_int = 1234;

	rcu_read_lock();
	/* find the task with that pid */
	t = pid_task(find_pid_ns(pid, &init_pid_ns), PIDTYPE_PID);	
	if(t == NULL){
		pr_err("no such pid\n");
		rcu_read_unlock();
		return -ENODEV;
	}
	rcu_read_unlock();

	/* send the signal */
	ret = send_sig_info(SIG_TEST, &info, t);    //send the signal
	if (ret < 0) {
		pr_err("error sending signal\n");
		return ret;
	}

	return count;
}

static const struct file_operations my_fops = {
	.write = write_pid,
};

static int __init ksig_init(void)
{
	pr_info("into %s\n", __func__);
	/* we need to know the pid of the user space process
 	 * -> we use debugfs for this. As soon as a pid is written to 
 	 * this file, a signal is sent to that pid
 	 */
	/* only root can write to this file (no read) */
	file = debugfs_create_file("signalconfpid", 0200, NULL, NULL, &my_fops);
	return 0;
}
static void __exit ksig_exit(void)
{
	pr_info("exit ksig module\n");
	debugfs_remove(file);
}

module_init(ksig_init);
module_exit(ksig_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ksig module");
MODULE_AUTHOR("daveti");

 

userspace :

init 時由 ioctl 把 pid丟到 kernel ,之後用 signal handler 來接

 


userspace 間的訊息傳遞:

使用 kill(pid , SIGNALID) ;// 此 kill 為傳遞 signal 之用

https://github.com/daveti/ksig/blob/master/signal_user.c

 

/*
 * signal_user.c
 * Signal recving program in the user space
 * Originated from http://people.ee.ethz.ch/~arkeller/linux/code/signal_user.c
 * Modified by daveti
 * Aug 23, 2014
 * root@davejingtian.org
 * http://davejingtian.org
 */
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>

#define SIG_TEST 44 /* we define our own signal, hard coded since SIGRTMIN is different in user and in kernel space */ 

void receiveData(int n, siginfo_t *info, void *unused)
{
	printf("received value %i\n", info->si_int);
}

int main(int argc, char **argv)
{
	int configfd;
	char buf[10];
	/* setup the signal handler for SIG_TEST 
 	 * SA_SIGINFO -> we want the signal handler function with 3 arguments
 	 */
	struct sigaction sig;
	sig.sa_sigaction = receiveData;
	sig.sa_flags = SA_SIGINFO;
	sigaction(SIG_TEST, &sig, NULL);

	/* kernel needs to know our pid to be able to send us a signal ->
 	 * we use debugfs for this -> do not forget to mount the debugfs!
 	 */
	configfd = open("/sys/kernel/debug/signalconfpid", O_WRONLY);
	if(configfd < 0) {
		perror("open");
		return -1;
	}
	sprintf(buf, "%i", getpid());
	if (write(configfd, buf, strlen(buf) + 1) < 0) {
		perror("fwrite"); 
		return -1;
	}
	
	return 0;
}

 

arrow
arrow
    全站熱搜

    立你斯 發表在 痞客邦 留言(0) 人氣()