Sunday, March 21, 2010

Sample App to test whether high res timers are available

#include
#include
#include


int check_timer(void);

int main()
{

if (check_timer())
fprintf(stderr,"NO: High resolution timers not available\n");
else
fprintf(stderr,"YES: High resolution timers are available\n");

return 0;

}

int check_timer(void)
{
struct timespec ts;

if (clock_getres(CLOCK_MONOTONIC, &ts))
return 1;

return (ts.tv_sec != 0 || ts.tv_nsec != 1);
}

Monday, March 8, 2010

RT Linux



1) Download the rt patch that is closer to kernel version that you are using
2) Apply the patch. This might be painful sometimes as some files like hrtimer.c would be the most modified. The patch might fail for these files depending upon the gap between the kernel version and rt patch version
3)Rebuild the kernel

Now that the kernel is made RT, we should make the thread RT. This would be done as follows

int create_thread()
{
unsigned int ulRetval = 0;

ulRetval = pthread_attr_init(&stThreadAttr);
ulRetval = pthread_attr_setinheritsched(&stThreadAttr, PTHREAD_EXPLICIT_SCHED);
ulRetval = pthread_attr_setschedpolicy(&stThreadAttr, SCHED_FIFO);
param.sched_priority = 45; (less than 50)
ulRetval = pthread_attr_setschedparam(&stThreadAttr, ¶m);
slReturn = pthread_create( &thread, &stThreadAttr, func1, NULL);
}

Linux Address Types

The following is a list of address types used in Linux
User virtual addresses

These are the regular addresses seen by user-space programs. User addresses are either 32 or 64 bits in length, depending on the underlying hardware architecture, and each process has its own virtual address space.

Physical addresses

The addresses used between the processor and the system's memory. Physical addresses are 32- or 64-bit quantities; even 32-bit systems can use 64-bit physical addresses in some situations.

Bus addresses

The addresses used between peripheral buses and memory. Often they are the same as the physical addresses used by the processor, but that is not necessarily the case. Bus addresses are highly architecture dependent, of course.
Kernel logical addresses

These make up the normal address space of the kernel. These addresses map most or all of main memory, and are often treated as if they were physical addresses. On most architectures, logical addresses and their associated physical addresses differ only by a constant offset. Logical addresses use the hardware's native pointer size, and thus may be unable to address all of physical memory on heavily equipped 32-bit systems. Logical addresses are usually stored in variables of type unsigned long or void *. Memory returned from kmalloc has a logical address.

Kernel virtual addresses

These differ from logical addresses in that they do not necessarily have a direct mapping to physical addresses. All logical addresses are kernel virtual addresses; memory allocated by vmalloc also has a virtual address (but no direct physical mapping). The function kmap, described later in this chapter, also returns virtual addresses. Virtual addresses are usually stored in pointer variables.

If you have a logical address, the macro __pa() (defined in ) will return its associated physical address. Physical addresses can be mapped back to logical addresses with __va(), but only for low-memory pages.

Low memory

Memory for which logical addresses exist in kernel space. On almost every system you will likely encounter, all memory is low memory.

High memory

Memory for which logical addresses do not exist, because the system contains more physical memory than can be addressed with 32 bits.

MMAP with example

Mapping a device means associating a range of user-space addresses to device memory. Whenever the program reads or writes in the assigned address range, it is actually accessing the device. In the X server example, using mmap allows quick and easy access to the video card's memory. For a performance-critical application like this, direct access makes a large difference.



mmap.c
#include <linux/version.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#ifdef MODVERSIONS
# include <linux/modversions.h>
#endif
#include <asm/io.h>

/* character device structures */
static dev_t mmap_dev;
static struct cdev mmap_cdev;

/* methods of the character device */
static int mmap_open(struct inode *inode, struct file *filp);
static int mmap_release(struct inode *inode, struct file *filp);
static int mmap_mmap(struct file *filp, struct vm_area_struct *vma);

/* the file operations, i.e. all character device methods */
static struct file_operations mmap_fops = {
.open = mmap_open,
.release = mmap_release,
.mmap = mmap_mmap,
.owner = THIS_MODULE,
};

// internal data
// length of the two memory areas
#define NPAGES 16
// pointer to the vmalloc'd area - alway page aligned
static char *vmalloc_area;

/* character device open method */
static int mmap_open(struct inode *inode, struct file *filp)
static int mmap_open(struct inode *inode, struct file *filp)
{
return 0;
}
/* character device last close method */
static int mmap_release(struct inode *inode, struct file *filp)
{
return 0;
}
// helper function, mmap's the vmalloc'd area which is not physically contiguous
int mmap_vmem(struct file *filp, struct vm_area_struct *vma)
{
int ret;
long length = vma->vm_end - vma->vm_start;
unsigned long start = vma->vm_start;
char *vmalloc_area_ptr = (char *)vmalloc_area;
unsigned long pfn;

printk(KERN_INFO"mmap_vmem is invoked\n");
/* check length - do not allow larger mappings than the number of
pages allocated */
if (length > NPAGES * PAGE_SIZE)
return -EIO;

/* loop over all pages, map it page individually */
while (length > 0) {
pfn = vmalloc_to_pfn(vmalloc_area_ptr);
if ((ret = remap_pfn_range(vma, start, pfn, PAGE_SIZE,
PAGE_SHARED)) < 0) {
return ret;
}
start += PAGE_SIZE;
vmalloc_area_ptr += PAGE_SIZE;
length -= PAGE_SIZE;
}
return 0;
}

/* character device mmap method */
static int mmap_mmap(struct file *filp, struct vm_area_struct *vma)
{
printk(KERN_INFO"mmap_mmap is invoked\n");
/* at offset 0 we map the vmalloc'd area */
if (vma->vm_pgoff == 0) {
return mmap_vmem(filp, vma);
}
#if 0
/* at offset NPAGES we map the kmalloc'd area */
if (vma->vm_pgoff == NPAGES) {
return mmap_kmem(filp, vma);
}
#endif
/* at any other offset we return an error */
return -EIO;
}

/* module initialization - called at module load time */
static int __init mmap_init(void)
{
int ret = 0;
int i;
char *my_char_ptr, *my_char_ptr_2;
int *my_int_ptr;
/* allocate a memory area with vmalloc. */
#if 1
if ((vmalloc_area = (char *)vmalloc(NPAGES * PAGE_SIZE)) == NULL) {
ret = -ENOMEM;
goto out_vfree;
}
#endif
/* get the major number of the character device */
if ((ret = alloc_chrdev_region(&mmap_dev, 0, 1, "mmap")) < 0) {
printk(KERN_ERR "could not allocate major number for mmap\n");
goto out_vfree;
}

/* initialize the device structure and register the device with the kernel */
cdev_init(&mmap_cdev, &mmap_fops);
if ((ret = cdev_add(&mmap_cdev, mmap_dev, 1)) < 0) {
printk(KERN_ERR "could not allocate chrdev for mmap\n");
goto out_unalloc_region;
}
#if 0
/* mark the pages reserved */
for (i = 0; i < NPAGES * PAGE_SIZE; i+= PAGE_SIZE) {
SetPageReserved(vmalloc_to_page((void *)(((unsigned long)vmalloc_area) + i)));
}
#endif
/* store a pattern in the memory - the test application will check for it */
#if 1
my_char_ptr = vmalloc_area;
memcpy(my_char_ptr," ------This is from kernel space",100); my_int_ptr = (int *)vmalloc_area + 100;
*my_int_ptr = 1000;
my_char_ptr_2 = (char *)((int *)vmalloc_area + 100 + 4);
memcpy(my_char_ptr_2," ----This is second message from kernel space",100);

#endif
return ret;

out_unalloc_region:
unregister_chrdev_region(mmap_dev, 1);
out_vfree:
vfree(vmalloc_area);

return ret;
}

/* module unload */
static void __exit mmap_exit(void)
{
int i;

/* remove the character deivce */
cdev_del(&mmap_cdev);
unregister_chrdev_region(mmap_dev, 1);
#if 1
/* unreserve the pages */
for (i = 0; i < NPAGES * PAGE_SIZE; i+= PAGE_SIZE) {
SetPageReserved(vmalloc_to_page((void *)(((unsigned long)vmalloc_area) + i)));
}
#endif
/* free the memory areas */
vfree(vmalloc_area);
// kfree(kmalloc_ptr);
}

module_init(mmap_init);
module_exit(mmap_exit);
MODULE_DESCRIPTION("mmap demo driver");
MODULE_AUTHOR("Martin Frey ");
MODULE_LICENSE("Dual BSD/GPL");

Build this as a module for some built kernel and insert the module

mmap_test.c
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>

#define NPAGES 16

/* this is a test program that opens the mmap_drv.
It reads out values of the kmalloc() and vmalloc()
allocated areas and checks for correctness.
You need a device special file to access the driver.
The device special file is called 'node' and searched
in the current directory.
To create it
- load the driver
'insmod mmap_mod.o'
- find the major number assigned to the driver
'grep mmapdrv /proc/devices'
- and create the special file (assuming major number 254)
'mknod node c 254 0'
*/

char *my_first_ptr;

int main(void)
{
int fd;
unsigned char *vadr;
unsigned int *kadr;

int len = NPAGES * getpagesize();

if ((fd=open("node", O_RDWR|O_SYNC))<0)
{
perror("open");
exit(-1);
}

vadr = mmap(0, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (vadr == MAP_FAILED)
{
perror("mmap");
exit(-1);
}

printf("The contents of the virtual address space in user space is %s\n", vadr);
memcpy(vadr,"This is from user space", 50);
if(munmap(vadr, len) == -1)
{
perror("munmap failed\n");
}
close(fd);
return(0);
}


Build this as a user space application and run this application
Note: You might have to create a node using mknod function. Create as explained in the mmap_test.c file and then run
The application should print the message "This is a message from kernel"