Failed to read APIC timer registers - linux

I am writing a Linux kernel module to read dump local APIC timer registers.
I am using Ubuntu 16.04 desktop on X86_64 platform.
X2APIC is disabled, and nohz=off in grub.cfg.
I am using following codes to read APIC timer registers.
#include <linux/slab.h>
#include <linux/time.h>
#include <asm/string.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/hrtimer.h>
#include <linux/ktime.h>
#include <asm/apic.h>
void read_apic_timer(void)
{
printk("APIC_TDCR = 0x%x\n", apic_read(APIC_TDCR));
printk("APIC_TMICT = 0x%x\n", apic_read(APIC_TMICT));
printk("APIC_TMCCT = 0x%x\n", apic_read(APIC_TMCCT));
}
static int __init timer_init(void)
{
read_apic_timer();
return 0;
}
static void __exit timer_exit(void)
{
printk("module uninstalling\n");
}
module_init(timer_init);
module_exit(timer_exit);
MODULE_LICENSE("GPL");
And I got these,
[ 5619.047497] APIC_TDCR = 0x0
[ 5619.047498] APIC_TMICT = 0x0
[ 5619.047499] APIC_TMCCT = 0x0
To my surprise, initial counter and current counter are all 0, is it correct?
Or did I miss something or make something wrong?

I think I get the answer. It is because the CPU supports TSC deadline feature/mode for LAPIC timer. In this mode, APIC_TDCR/TMICT/TMCCT are not being used. That is it.

Related

Are the interrupts in Linux queued

I wrote a sample driver which disables keyboard interrupt for few seconds, and when i press keys at that duration, i get the pressed keys on the console when the interrupt is enabled?
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irqflags.h>
#include <linux/interrupt.h>
unsigned int irq = 1;
module_param(irq, int, 0);
static int __init my_init(void)
{
pr_info("module is loaded on processor:%d\n", smp_processor_id());
pr_info("Disabling Interrupt:%u\n", irq);
disable_irq(irq);
pr_info("Disabled Interrupt:%u\n", irq);
mdelay(10000L);
pr_info("Enabling Interrupt:%u\n", irq);
enable_irq(irq);
pr_info("Enabled Interrupt:%u\n", irq);
return 0;
}
static void __exit my_exit(void)
{
}
MODULE_LICENSE("GPL");
module_init(my_init);
module_exit(my_exit);

Assign a hexadecimal address directly to a pointer in LKM code but get different result

I wrote the following code:
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/syscalls.h>
#include <linux/version.h>
void **sys_call_table;
int __init kaslr_init(void)
{
#if KERNEL_VERSION(2, 6, 32) == LINUX_VERSION_CODE // on CentOS 6
sys_call_table = (void *) 0xffffffff816004c0;
#elif KERNEL_VERSION(4, 19, 0) == LINUX_VERSION_CODE // on Arch Linux
sys_call_table = (void *) 0xffffffff81c001c0;
#elif KERNEL_VERSION(3, 10, 0) == LINUX_VERSION_CODE // on CentOS 7
sys_call_table = (void *) 0xffffffff97c03300;
#endif
pr_err("%p\n", sys_call_table);
#if KERNEL_VERSION(4, 19, 0) != LINUX_VERSION_CODE
if (sys_call_table[__NR_close] == sys_close)
pr_err("Bingo!\n");
#endif
return 0;
}
void __exit kaslr_exit(void)
{
pr_err("Bye\n");
}
module_init(kaslr_init);
module_exit(kaslr_exit);
MODULE_LICENSE("GPL");
And get the results:
// on CentOS 6
ffffffff816004c0
Bingo!
// on CentOS 7
[ 1375.358780] ffffffff97c03300
[ 1375.361958] Bingo!
// on Arch Linux
[ 1185.136873] 00000000bd3b9e65
From the result, I got a user-space address on Arch.
First I thought it maybe the reason of kaslr, so I disabled it by adding nokaslr parameter in /etc/default/grub and rebooted. But it still remained.
Is there any kernel security mechanism which leads to such the result?
Heading
On Arch Linux (newer kernel) kernel pointer scrambling enabled by default. Use %px format.
See Pointer Types in printk formats for details (pr_err is just wrapper around printk)

Implementing a system call for CPU hotplug on RPI3/ModelB

My goal is to implement a system call in linux kernel that enables/disables a CPU core.
First, I implemented a system call that disbales CPU3 in a 4-core system.
The system call code is as follows:
#include <linux/kernel.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <linux/cpumask.h>
asmlinkage long sys_new_syscall(void)
{
unsigned int cpu3 = 3;
set_cpu_online (cpu3, false) ; /* clears the CPU in the cpumask */
printk ("CPU%u is offline\n", cpu3);
return 0;
}
The system call was registered correctly in the kernel and I enabled 'cpu hotplug' feature during kernel configuration ( See picture )
Kernel configuration:
The kernel was build . But when I check the system call using test.c :
#include <stdio.h>
#include <linux/kernel.h>
#include <sys/syscall.h>
#include <unistd.h>
long new_syscall(void)
{
return syscall(394);
}
int main(int argc, char *argv[])
{
long int a = new_syscall();
printf("System call returned %ld\n", a);
return 0;
}
The OS frezzes !
What am I doing wrong ?
why would you want to implement a dedicated syscall? the standard way of offlining cpus is through writes to sysfs. in the extremely unlikely case there is a valid reason to create a dedicated syscall you will have to check how offlining works under the hood and repeat that.
set_cpu_online (cpu3, false) ; /* clears the CPU in the cpumask */
your own comment strongly suggests this is too simplistic. for instance what if the thread executing this is running on said cpu? what about threads which are queued on it?
and so on
This is kind of an old topic, but you can put a CPU up/down in kernel land by using the functions cpu_up(cpu_id) and cpu_down(cpu_id), from include/linux/cpu.h.
It seems that set_cpu_online is not exported since it doesn't seems to be safe from other kernel parts stand point (it doesn't consider process affinity and other complexities, for example).
So, your system call could be written as:
asmlinkage long sys_new_syscall(void)
{
unsigned int cpu3 = 3;
cpu_down(cpu3) ; /* clears the CPU in the cpumask */
printk ("CPU%u is offline\n", cpu3);
return 0;
}
I have an example module using those methods here: https://github.com/pappacena/cpuautoscaling.

How can I get rq structure in linux kernel?

I made a linux module program to get rq structure in CPU like this
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <../kernel/sched/sched.h>
int init_hello(void)
{
int cpu;
for_each_online_cpu(cpu)
{
struct rq *rq = cpu_rq(cpu)
printk( KERN_ALERT "rq->curr->pid = %d", rq->curr->pid);
}
}
...
Both 'Makefile' and 'insmod hello.ko' are done, But I got a error message like this
...
[30557.012624] hello: Unknown symbol runqueues (err 0)
How can I solve this problem?

Accessing RTC I2C chip connecting to FPGA through GPIO

I need to get data from a RTC device (stm41t83) through I2C. The device is directly connected to two pins of a GPIO. I tried to use the i2c-gpio driver with the piece of code below,
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c-gpio.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#define GPIO_RTC_SDA 100
#define GPIO_RTC_SCL 99
MODULE_DESCRIPTION("i2c via gpio module");
MODULE_LICENSE("GPL");
static struct i2c_gpio_platform_data rtc_device_data = {
.sda_pin = GPIO_RTC_SDA,
.scl_pin = GPIO_RTC_SCL,
.udelay = 25
};
static struct platform_device i2c_gpio_bus_rtc = {
.name = "i2c-gpio",
.id = 0,
.dev = {
.platform_data = &rtc_device_data,
}
};
static int __init i2c_gpio_bus_init(void)
{
return platform_device_register(&i2c_gpio_bus_rtc);
}
static void __exit i2c_gpio_bus_exit(void)
{
platform_device_unregister(&i2c_gpio_bus_rtc);
}
module_init(i2c_gpio_bus_init);
module_exit(i2c_gpio_bus_exit);
but when I use the i2cdetect utility from the i2c tools package, I can't see my RTC device located at 0x68. Do I need to add some other stuff to get it working?
Thanks for answers!
jrm
I finally solved my problem! I was not a software problem but rather a FPGA configuration issue. Follow this link, post #13 to know the answer.
Thanks to all ;-)

Resources