local_irq_disable()is used to disable all interrupts on the current processor
i wrote a basic code to test local_irq_disable().
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irqflags.h>
static int __init my_init(void)
{
pr_info("module is loaded on processor:%d\n", smp_processor_id());
local_irq_disable();
ssleep(10);
local_irq_enable();
return 0;
}
static void __exit my_exit(void)
{
}
MODULE_LICENSE("GPL");
module_init(my_init);
module_exit(my_exit);
When i load this on my system, it prints the following message:
[10478.930188] module is loaded on processor:5
And when i run "watch -d -n 0.2 'cat /proc/interrupts'", it still shows interrupts on those processor, what i am missing here?
Related
There is page_address() in linux kernel to get the virtual address of a page.
However I find that it is not work when a page is allocted by vmalloc() in following demo.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/slab.h>
MODULE_LICENSE("GPL");\
char *p1,*p2;
static void check_vmalloc(const void *addr)
{
if(is_vmalloc_addr(addr))
{
struct page *p=vmalloc_to_page(addr);
printk("%lx from vmalloc. PFN %lu. VirtualAddr %lx",(unsigned long)addr,page_to_pfn(p),page_address(p));
if(is_vmalloc_addr(page_address(p)))
{
printk("VirtualAddr %lx is vmalloc",page_address(p));
}
else
{
printk("VirtualAddr %lx is not vmalloc",page_address(p));
}
}
else
{
printk("%lx not from vmalloc\n",(unsigned long)addr);
}
}
static int __init lkm_example_init(void) {
printk("pid %d\n",current->pid);
p1=vmalloc(10);
*p1=123;
check_vmalloc(p1);
p2=kmalloc(10,GFP_KERNEL);
*p2=123;
check_vmalloc(p2);
return 0;
}
static void __exit lkm_example_exit(void) {
printk("Goodbye\n");
vfree(p1);
kfree(p2);
}
module_init(lkm_example_init);
module_exit(lkm_example_exit);
output
So, if I want to find the virtual address of a page which is allocated by vmalloc(), what should I do?
And could you tell me how to judge whether a page is allocated by vmalloc()?
I would like to write some code (for example as a small kernel module) to instrument local interrupts on Linux running on the x86-64 architecture, i.e. I would like to write some kind of handler that is called by the kernel every time a local interrupt is triggered by the APIC.
The handler would then check whether a certain process is currently running and inspect said process' memory.
I realize that what I am trying to do may not be good engineering practice, but my aim is to create a hacky one-off solution for exploration/research purposes.
In the ideal case, there would be some kind of function similar to request_irq [1] (which as far as I can tell is used for handling interrupts from devices like keyboards, network cards, ...) allowing me to tell the kernel to run my code every time a local timer interrupt occurs.
Does anybody have any pointers on how to accomplish this?
Does the kernel provide an API for registering a handler for local interrupts?
If not, I could directly modify the kernel's source code for handling interrupts. Where in the kernel would I find this code?
Edit: Here is what my research so far has found.
TLDR:request_irq is not the way to hook local timer interrupts.
According to Understanding the Linux Kernel, Table 4.2 [2], the interrupt vector 0xef is allocated to Local APIC timer interrupts. The kernel source confirms this [3].
Since request_irq takes an interrupt vector as its first argument, let's try registering a handler for this vector inside a kernel module:
#include <linux/module.h>
#include <linux/kernel.h> // included for KERN_INFO
#include <linux/init.h> // included for __init and __exit macros
#include <linux/interrupt.h> // included for IRQF_ and request_irq
#include <linux/irqreturn.h> // included for IRQ_NONE
#include <asm/irq_vectors.h> // included for LOCAL_TIMER_VECTOR
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Instrument local timer interrupts");
static int DEVICE_COOKIE = 1;
static int count = 0;
static irqreturn_t handler(int irq, void *dev) {
count++;
return IRQ_NONE;
}
static int __init test_init(void) {
int status;
printk(KERN_INFO "Running request_irq\n");
status = request_irq(
LOCAL_TIMER_VECTOR,
&handler,
IRQF_TIMER,
"foobar",
&DEVICE_COOKIE);
if (status == 0) {
printk(KERN_INFO "Successfully installed handler\n");
return 0;
} else {
printk(
KERN_INFO "Failed to install handler. error code: %d\n",
status);
return -1;
}
}
static void __exit test_cleanup(void) {
free_irq(LOCAL_TIMER_VECTOR, &DEVICE_COOKIE);
printk(KERN_INFO "Goodbye kernel. I saw %d interrupts.\n", count);
}
module_init(test_init);
module_exit(test_cleanup);
When we try to insert the module with insmod, request_irq returns -EINVAL:
[74890.287173] Running request_irq
[74890.287174] Failed to install handler. error code: -22
So where does the -EINVAL come from?
Reading through the kernel source, we find that request_irq is just a wrapper around request_threaded_irq [4]. request_threaded_irq calls irq_to_desc and returns -EINVAL if the call fails. We can easily check whether this is the case with another small kernel module:
#include <linux/kernel.h> // included for KERN_INFO
#include <linux/init.h> // included for __init and __exit macros
#include <linux/interrupt.h> // included for IRQF_ and request_irq
#include <linux/irqreturn.h> // included for IRQ_NONE
#include <asm/irq_vectors.h> // included for LOCAL_TIMER_VECTOR
#include <linux/irqnr.h> // included for irq_to-desc
#include <linux/irqdesc.h> // included for irq_desc
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Call irq_to_desc(LOCAL_TIMER_VECTOR)");
static int __init test_init(void) {
struct irq_desc *desc;
desc = irq_to_desc(LOCAL_TIMER_VECTOR);
if (!desc) {
printk(KERN_INFO "irq_to_desc(LOCAL_TIMER_VECTOR) failed");
return -1;
}
return 0;
}
static void __exit test_cleanup(void) {
}
module_init(test_init);
module_exit(test_cleanup);
And indeed it fails:
[75787.142533] irq_to_desc(LOCAL_TIMER_VECTOR) failed
[1] www.makelinux.net/books/lkd2/ch06lev1sec3
[2] www.safaribooksonline.com/library/view/understanding-the-linux/0596005652/ch04s06.html
[3] lxr.free-electrons.com/source/arch/x86/include/asm/irq_vectors.h?v=4.8#L108
[4] lxr.free-electrons.com/source/kernel/irq/manage.c?v=4.8#L1634
Yesterday I installed a very simple kernel module in my embedded Linux system. "hello.ko".
When I install this module to our system, it's normally:
#insmod hello.ko
Initing kernel module
#
#lsmod
hello 638 0 - Live 0xf628f000
But when I remove this kernel module, It can be removed normally but rmmod notice 'hello.ko' not found
# rmmod hello
Cleaning kernel module
rmmod: module 'hello' not found
#lsmod <------------------- already be removed
#
# uname -a
# Linux SWITCH 2.6.32 #8 Thu Jun 23 20:34:48 KST 2016 ppc GNU/Linux
It's very strange. Could anyone explain for me why 'hello.ko' is removed but there's log 'rmmod module not found'?
The following are source code of hello.ko
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/config.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/string.h>
int init_module(void)
{
printk (KERN_EMERG "Initing kernel module\n");
return 0;
}
void cleanup_module(void)
{
printk (KERN_EMERG "Cleaning kernel module\n");
}
MODULE_DESCRIPTION ("Kernel function replacement module");
MODULE_AUTHOR ("DASAN Networks Inc.");
MODULE_LICENSE ("GPL");
You need to add few things in my opinion __init and __exit macros and module_init and module_exit macros, try with:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/string.h>
static int __init init_example(void)
{
printk (KERN_EMERG "Initing kernel module\n");
return 0;
}
static void __exit cleanup_example(void)
{
printk (KERN_EMERG "Cleaning kernel module\n");
}
module_init(init_example);
module_exit(cleanup_example);
MODULE_DESCRIPTION ("Kernel function replacement module");
MODULE_AUTHOR ("DASAN Networks Inc.");
MODULE_LICENSE ("GPL");
I'm trying to get an interrupt whenever the UART line gets data on the BeagleBone Black. However, I'm stuck on figuring out how to register the handler. I can use request_irq() to register GPIO interrupts for example, but trying to get the irq for the UART doesn't seem to work. I believe 73 is the right number, as after registering it, reading from /dev/ttyO1 (the UART dev file) throws an error, but the handler never triggers.
Am I approaching this right? What I'm currently trying is below. Thanks.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#define KERNEL_NAME "TestKernel"
#define IRQ_NUMBER 73
int id = 8273643;
irq_handler_t handler(int irq, void* dev_id, struct pt_regs* regs)
{
printk(KERN_ALERT KERNEL_NAME ": Handler called, irq: %d\n", irq);
return (irq_handler_t)IRQ_HANDLED;
}
static int __init driver_entry(void)
{
int result = request_irq(IRQ_NUMBER, (irq_handler_t)handler, 0, "test", &id);
printk(KERN_ALERT KERNEL_NAME ": Insert successful, result: %d\n", result);
return result;
}
static void __exit driver_exit(void)
{
free_irq(IRQ_NUMBER, NULL);
printk(KERN_ALERT KERNEL_NAME ": Cleanup\n");
}
module_init(driver_entry);
module_exit(driver_exit);
MODULE_LICENSE("GPL");
I have a simple module, written as follows:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
static int __init hellomod_init(void)
{
printk(KERN_DEBUG, "Hello, world!\n");
return 0;
}
static void __exit hellomod_exit(void)
{
printk(KERN_DEBUG, "Goodbye, world!");
}
module_init(hellomod_init);
module_exit(hellomod_exit);
and
$ cat /proc/sys/kernel/printk
7 7 7 7
so that any level messages should output.
The module loads and this can be verified with lsmod, however no output is produced when loading or unloading the module and checking dmesg.
I have tried replacing KERN_DEBUG with lower levels and still no output, so I don't think the log level is the issue.
How else can I verify the hellomod_init() function is called? If it is not being called, what is my error?
I am running and compiling against kernel version 4.6.1-2 on Arch Linux.
There shouldn't be a comma after KERN_DEBUG. So it should look something like this:
static int __init hellomod_init(void)
{
printk(KERN_DEBUG "Hello, world!\n");
return 0;
}