IO Mapped IO and Memory Mapped IO

Sounds like hardware terms, yes you are right. Today I will share some words what I learned regarding this. When I tried to write a Linux Device Driver I met with this requirement, so it is important for any Driver Developer to know this.

Mapping IO devices

Micro processor usually offers two mechanisms (refer title for their names) for connecting an external IO device with its address bus. For any IO device both methods are identical, it normally need to decode its address from address bus and read or write data into data bus.

Memory Mapped IO

IO devices are mapped along with RAM and ROM in system memory map.

Advantage: Simple instructions which is used to access Memory regions can be applied for IO devices too. So, accessing a hardware IO device becomes as much simple as that we are accessing a normal memory region.

Disadvantage: Is that inorder to access a single device it becomes necessary to decode all the address lines. For a 16-bit address bus it requires as much logics(gates) to resolve all the 16 address lines, it increases the hardware cost.

Example

ARM

IO Mapped IO

IO devices are mapped into separate address space. Hence the address lines gets segregated to port of IO devices and Memory. It results with small number of address lines in port address space and more number of lines in memory address space. For accessing IO ports special instructions are needed, hence more instructions are involved in this mechanisms (separate for IO devices and Memory).

Example

Intel’s X86.

Corrections are always invited..!

Enjoy…!

Advertisements

Windows System Restore from Safe Mode Command Prompt

You all may be wondering why this Linux guy try to tell some thing about Windows. But the truth is Everybody will start working with computer only using WINDOWS at beginning. But still I will not support WINDOWS due to….. Today I encountered a big problem… My laptop is dual bootable holds lovable Linux and hate – able Windows. After long time I booted my laptop using Windows and while shutting down it started configuring updates…blah..blah…(which I was postponing from the last month to save my time). But when I rebooted once again with Windows 7 I can see all the initial steps as normal and my machine started applying updates but it got hang at certain point prompting as follows…

“Setting up Personalized settings for :

Web platform Customizations”

You may google and learn more about the same. I waited for some time, but still same problem persists. It grabbed much more time. So as per Windows support team I followed this. But nothing worked for me, as per the Method 3: suggested by the Support Engineer, I planned to restore my system. But I faced another problem, I followed everything as per the given procedure, at last it prompted me to give password for the user (not even Administrator’s password) I feel shy to say that I don’t know my own password 😉

So I decided to acheive this in some other way.. At last a youtube video helped me. Actually I wrote this blog only to reveal this top secret to you all 😉 As per the video,

1) Turn ON system at Safe mode with command prompt option(this can be achieved only holding F8 key before Windows logo gets displayed during boot up).

2) Your system will boot up normally and finally it will through you in windows command prompt

3) Follow each stop as below inside command prompt

blah> cd \Windows\System32\restore

blah> rstrui

Whereas, rstrui stands for restore user interface

4) You will see normal restore screen and after selecting the appropriate restore point your system will start to restore before to that point.

Easy ….?!

Enjoy….!

Update: After restoring my system worked fine but, again the same updates made me crazy and I followed previous procedure.

Moral of Story : Skip such updates before they mess-up your system and be patient till the windows guys trigger out some solution for this particular problem (As for as my knowledge I was not able to get any solution from any search engine &&& I will appreciate anyone comes with solution).

Enjoy….!

Update : 04 / 07 / 2013

Hi again, this same update made same problem. But this time I saw some other solution to solve this. But I don’t know whether this solutions will help me from any threads in future.

Steps as follow,

1) When the same black screen prompting

“Setting up Personalized settings for :

Web platform Customizations”

appears, press (Ctrl + Alt + Del) at a same time.

2) As normal you will see a screen with options like lock, log off, change password, and start task manager.

3) Select “Start Task Manager”, it will throw you in task manager screen

4) Select “New task”

5) Then a new will appears, type “cmd” and press “OK”

6) Now after getting command prompt type this command shutdown/r.

7) You will see a notification saying that Windows will shutdown in less than a minute.

8) After restart your Windows will work normally……!

Enjoy…!

A Basic Character Driver – to read and write messages

I will discuss a basic character driver, which can read last character and display. It is a simple driver one can develop much better driver based upon this..

For any character driver there must exists a file under /dev directory, this file can be automatically created by using appropriate Kernel APIs such as class_create, device_create, class_destroy, device_destroy prototyped under #include <linux/device.h>. But here I will create them manually for the sake of showing simple and basic driver source code.

$ sudo mknod /dev/dummy_memory c 60 0

and make it read and writable by everyone

$ sudo chmod 666 /dev/dummy_memory

Here major and minor numbers are selected by myself, but this kind of programming is a bad practice, try to achieve this using respective APIs which I discussed earlier.

Start writing

Open any of your favorite editor, where as mine is vim

$ vim dummy_memory.c

Needed for any Kernel Module,

$ #include <linux/module.h>

Needed for KERN_INFO, KERN_ALERT kind of macros,

$ #include <linux/kernel.h>;

Needed for matching versions,

$ #include <linux/version.h>

Global Declaration of struct file_operations

Virtual File System lies in Kernel space just above character driver and low-level I/F. This VFS decodes the file type and transfers the file operations to appropriate device driver. Now for VFS to pass the device file operations onto the driver, it should have been informed about it. That is what we call as registering the file operations by driver with VFS. Basically it involves by using file_operations structure, which holds appropriate functions to be performed during usage.

static struct file_operations memory_fops = 

{

.owner = THIS_MODULE,

.open = memory_open,

.release = memory_release,

.read = memory_read,

.write = memory_write,

};

And also I declared two more global variables for my usage,

static int memory_major = 60;

static char *memory_buffer;

module_init(memory_init);

static int __init memory_init(void)
{
int result;

result = register_chrdev(memory_major,”dummy_memory”,&memory_fops);

if(result < 0)
{
printk(KERN_INFO “<1> dummy_memory : Cannot obtain major number %d\n”,memory_major);
return result;
}

memory_buffer = kmalloc(1,GFP_KERNEL);

if(!memory_buffer)
{
result = -ENOMEM;
goto fail;
}

printk(KERN_INFO “<1>Inserting memory module\n”);

return 0;

fail:
memory_exit();
return result;
}

Here two things to be noted,

1) register_chrdev function

Within the driver, in order to link it with its corresponding /dev file in kernel space, the register_chrdev function is used. It is called with three arguments: major number, a string of characters showing the module name, and a file_operations structure which links the call with the file functions it defines. FYI register_chrdev and deregister_chrdev is prototyped under #include <linux/fs.h>

2) kmalloc

Also, note the use of the kmalloc function. This function is used for memory allocation of the buffer in the device driver which resides in kernel space. Its use is very similar to the well known malloc function. Refer Kernel API for more info. FYI kmalloc and kfree is prototyped under #include <linux/slab.h>

Finally, if registering the major number or allocating the memory fails, the module acts accordingly.

module_exit(memory_exit);

static void __exit memory_exit(void)
{
unregister_chrdev(memory_major,”dummy_memory”); // Freeing Major number

if(memory_buffer)
kfree(memory_buffer); // Freeing buffer memory

printk(KERN_INFO “<1>Removing memory module\n”);
}

It is reverse of previous, acts vice versa.

Opening device as file

The kernel space function, which corresponds to opening a file, is the member .open = my_open of the file_operations structure in the call to register_chrdev. In this case, it is the memory_open function. It takes as arguments: an inode structure, which sends information to the kernel regarding the major number and minor number; and a file structure with information relative to the different operations that can be performed on a file.

Neither of these functions will be covered in depth within this article.

When a file is opened, it’s normally necessary to initialize driver variables or reset the device. In this simple example, though, these operations are not performed.

static int memory_open(struct inode *i,struct file *f)
{
return 0; // success
}

Closing device as file

The corresponding function for closing a file, is the member .release = memory_release of the file_operations structure in the call to register_chrdev. In this particular case, it is the function memory_release, which has as arguments an inode structure and a file structure, just like before. When a file is closed, it’s usually necessary to free the used memory and any variables related to the opening of the device.

But, once again, due to the simplicity of this example, none of these operations are performed.

static int memory_release(struct inode *i,struct file *f)
{
return 0; // success
}

Reading the device

To read a device, the member .read = memory_read of the file_operations structure is used in the call to register_chrdev. This time, it is the function memory_read. Its
arguments are: a type file structure; a buffer (buf), from which the user space function will read; a counter with the number of bytes to transfer (count), which has the same value as the usual counter in the user space function; and finally, the position of where to start reading the file (f_pos).

In this simple case, the memory_read function transfers a single byte from the driver buffer
(memory_buffer) to user space with the function copy_to_user which is prototyped under #include <asm/uaccess.h>

static ssize_t memory_read(struct file *f,char *buf,size_t count,loff_t *f_pos)
{
copy_to_user(buf,memory_buffer,1);

if(*f_pos == 0)
{
*f_pos += 1;
return 1;
}

else
return 0;
}

Writing the device

To write to a device, member .write = memory_write of the
file_operations structure is used in the call to register_chrdev. It is the function memory_write, in this particular example, which has the following as arguments: a type file structure; buf, a buffer in which the user space function (fwrite) will write; count, a counter with the number of bytes to transfer, which has the same values as the usual counter in the user space function (fwrite); and finally, f_pos, the position of where to start writing in the file.

In this case, the function copy_from_user which is prototyped under #include <asm/uaccess.h> transfers the data from user space to kernel space.

static ssize_t memory_write(struct file *f,char *buf,size_t count,loff_t *f_pos)
{
char *tmp;

tmp = buf + count – 1;

copy_from_user(memory_buffer,tmp,1);

return 1;
}

At last, my driver will look a like,

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

#include <linux/fs.h> // prototype for register_chrdev() and unregister_chrdev()
#include <linux/slab.h> // kmalloc and kfree

#include <asm/uaccess.h> // copy_to_user and copy_from_user

int memory_major = 60;

char *memory_buffer;

static int memory_open(struct inode *i,struct file *f)
{
return 0; // success
}

static int memory_release(struct inode *i,struct file *f)
{
return 0; // success
}

static ssize_t memory_read(struct file *f,char *buf,size_t count,loff_t *f_pos)
{
copy_to_user(buf,memory_buffer,1);

if(*f_pos == 0)
{
*f_pos += 1;
return 1;
}

else
return 0;
}

static ssize_t memory_write(struct file *f,char *buf,size_t count,loff_t *f_pos)
{
char *tmp;

tmp = buf + count – 1;

copy_from_user(memory_buffer,tmp,1);

return 1;
}

static struct file_operations memory_fops =
{
.owner = THIS_MODULE,
.open = memory_open,
.release = memory_release,
.read = memory_read,
.write = memory_write,
};

static void __exit memory_exit(void)
{
unregister_chrdev(memory_major,”dummy_memory”); // Freeing Major number

if(memory_buffer)
kfree(memory_buffer); // Freeing buffer memory

printk(KERN_INFO “<1>Removing memory module\n”);
}

static int __init memory_init(void)
{
int result;

result = register_chrdev(memory_major,”dummy_memory”,&memory_fops);

if(result < 0)
{
printk(KERN_INFO “<1> dummy_memory : Cannot obtain major number %d\n”,memory_major);
return result;
}

memory_buffer = kmalloc(1,GFP_KERNEL);

if(!memory_buffer)
{
result = -ENOMEM;
goto fail;
}

printk(KERN_INFO “<1>Inserting memory module\n”);

return 0;

fail:
memory_exit();
return result;
}

module_init(memory_init);
module_exit(memory_exit);

MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“S MOHAMMED AUDHIL”);
MODULE_DESCRIPTION(“DUMMY MODULE to read and write /dev/dummy_memory file”);

I created a simple Makefile

obj-m += dummy_memory.o

KDIR := /usr/src/linux-headers-$(shell uname -r)

PWD := $(shell pwd)

defaults:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

Compiling

$ make

Output can be seen as follows,

Image

and dmesg

Image

Enjoy..!

Kernel Compilation inside Eclipse-CDT

Here is step by step procedure for LINUX KERNEL compilation inside Eclipse-CDT.

1) Download Eclipse-CDT and install

$ sudo apt-get install eclipse-cdt

2) Make a directory which holds kernel source

$ mkdir kernel_source

and copy kernel source code inside to this,

$ cp linux.x.xx/ kernel_source/ -r

3) Configure kernel with following options enabled, if your are looking for debugging kernel

$ make menuconfig

Enter inside Kernel Hacking section; select Kernel Debugging; check “Compile the kernel with debug info” and “Compile the kernel with frame pointers”.

4) Open Eclipse

$ eclipse

In order to save time, just disable automatic building and indexing, by navigating through following options,

Go to Window –> Preference –> General –> Workspace and disable the option “Build automatically”. To disable indexing, visit Window –> Preference –> General –> C/C++ –> Indexer. Select “No Indexer”.

To proceed, select File –> New –> C Project. Give a name to your project, uncheck “Use Default Location” and browse to your kernel source-code directory. From Project Type, select Makefile Project –> Empty Project. If you want to cross-compile the kernel, and you already have some other tool chain installed, you can choose it from “Toolchain”. Click Finish to complete this initial step.

5) Compiling linux kernel

Right click on the audhil directory, and select Build project option, Kernel will start to compile as shown below.

compilation At last you may see kernel image at arch/x86/boot/bzImage.

21