Thursday, 19 November 2015

setuid() system call

Have you thought what if your application which is running in you want to make system call which need to run as root user then how to make it work ???

May that why you are here !!!!

   #include <stdio.h>
   #include <stdlib.h>
   #include <sys/types.h>
   #include <unistd.h>

   int main()
   {
   setuid(0);
   system("kill 1090");
   return 0;
   }

$ gcc program.c -o program
$ sudo chown root.root program
$ sudo chmod 4755 program
$ ./program

The setuid, setgid, and sticky Permissions

Contributed by Tom Rhodes.
Other than the permissions already discussed, there are three other specific settings that all administrators should know about. They are the setuid, setgid, andsticky permissions.
These settings are important for some UNIX® operations as they provide functionality not normally granted to normal users. To understand them, the difference between the real user ID and effective user ID must be noted.
The real user ID is the UID who owns or starts the process. The effective UID is the user ID the process runs as. As an example, passwd(1) runs with the real user ID when a user changes their password. However, in order to update the password database, the command runs as the effective ID of the root user. This allows users to change their passwords without seeing a Permission Denied error.
The setuid permission may be set by prefixing a permission set with the number four (4) as shown in the following example:
# chmod 4755 suidexample.sh
ref:https://www.freebsd.org/doc/handbook/permissions.html

Tuesday, 13 October 2015

What is processor,assembler and programming language

How does the processor (CPU) work?

You might know that the CPU (Central Processing Unit, or simply processor) is the “brain” of the computer, controlling all other parts of the computer and performing various calculations and operations with data. But how does it achieve that?
Processor is a circuit that is designed to perform single instructions: actually a whole series of them, one by one. The instructions to be executed are stored in some memory, in a PC, it’s the operating memory. Imagine the memory like a large grid of cells. Each cell can store a small number and each cell has its own unique number – address. The processor tells the memory address of a cell and the memory responds with the value (number, but it can represent anything – letters, graphics, sound… everything can be converted to numerical values) stored in the cell. Of course, the processor can tell the memory to store a new number in a given cell as well.
Instructions themselves are basically numbers too: each simple operation is assigned its own unique numeric code. The processor retrieves this number and decides what to do: for example, number 35 will cause the processor to copy data from one memory cell to another, number 48 can tell it to add two numbers together, and number 12 can tell it to perform a simple logical operation called OR.
Which operations are assigned to which numbers is decided by the engineers who design a given processor, or it’s better to say processor architecture: they decide what number codes will be assigned to various operations (and of course, they decide other aspects of the processor, but that’s not relevant now). This set of rules is then called the architecture. This way, manufactures can create various processors that support a given architecture: they can differ in speed, power consumption, and price, but they all understand the same codes as same instructions.
Once the processor completes the action determined by the code (the instruction), it simply requests the following one and repeats the whole process. Sometimes it can also decide to jump to different places in the memory, for example to some subroutine (function) or jump a few cells back to a previous instruction and execute the same sequence again – basically creating a loop. The sequence of numerical codes that form the program is called machine code.

What are instructions and how are they used?

As I already mentioned, instructions are very simple tasks that the processor can perform, each one having its unique code. The circuit that makes up the processor is designed in a way to perform the given operations according to the codes it loads from the memory. The numeric code is often called opcode.
The operations that the instructions perform are usually very simple. Only by writing a sequence of these simple operations, can you make the processor perform a specific task. However, writing a sequence of numeric codes is quite tedious (though that’s how programming was done long ago), so the assembly programming language was created. It assigns opcodes (the numeric code) a symbol – a name that sort of describes what it does.
Given the previous examples, where number 35 makes the processor move data from one memory cell to another, we can assign this instruction name MOV, which is a short for MOVe. Number 48, which is the instruction that adds two numbers together gets the name ADD, and 12, which performs the OR logical operation, gets the name ORL.
The programmer writes a sequence of instructions – simple operations that the processor can perform, using these names, which are much easier to read than just numeric codes. Then he executes a tool named assembler (but often the term “assembler” is used also for the programming language, though technically it means the tool), which will convert these symbols to the appropriate numeric codes that can be executed by the processor.
However, in most cases, the instruction itself isn’t sufficient. For example, if you want to add two numbers together, you obviously need to specify them, the same goes for logical operations, or moving data from a memory cell to another: you need to specify the address of the source and the target cell. This is done by adding the so-called operands to the instruction – simply one or more values (numbers) that will provide additional information for the instruction needed to perform a given operation. The operands are stored in the memory too, along with the instruction opcodes.
For example, if you want to move data from a location with address 1000 to a location 1258, you can write:
MOV 1258, 1000
The first number being the target address and the second the source (in assembly, you usually write the target first, and the source as the second one, it’s quite common). The assembler (the tool that converts the source to the machine code) stores these operands too, so when the processor first loads the instruction opcodes, which will tell it that it must move data from one location to another. Of course, it needs to know from which location to move to what destination, so it will load the operand values from the memory too (they can be at addresses right after the instruction opcodes), and once it has all the necessary data, it will perform the operation.

USB enable and disable

I would show you how to enable and USB driver without taking out it from the port from command Line !!!!

Isn't it amazing :D !!!!!!

First see the usb drive by following command
$ lsusb
$ lsusb -t


To Disable the
echo '2-1' > /sys/bus/usb/drivers/usb/unbind

To Enable it
echo '2-1' > /sys/bus/usb/drivers/usb/bind

'2-1' is process that would enable or disable . I havnt gone in detail through code. You can go through code and let me know if anything new to add

Now protect your PC with from external USB attack. You can write a script that would disable the PC usb port.

Thank you

Keep Hacking !!!


Wednesday, 13 May 2015

ftrace code for userspace


/*
 * file : ne_ftrace_console_write.c
 * desc : a demo program that uses "ftrace" for viewing the kernel control 
 *        path taken when a write(2) is made to "/dev/tty1".
 *
 * notes: code based on snippets from 'Documentation/trace/ftrace.txt' 
 *
 * Siro Mugabi, Copyright (c) nairobi-embedded.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

#define prfmt(fmt) "%s:%d:: " fmt, __func__, __LINE__
#define prerr(fmt, ...) fprintf(stderr, prfmt(fmt), ##__VA_ARGS__);
static const char *find_debugfs(void)
{
    #undef  PATH
    #define PATH     256
    #define _STR(x) #x
    #define STR(x) _STR(x)

    static char debugfs[PATH + 1];
    static int debugfs_found;
    char type[100];
    FILE *fp;

    if (debugfs_found)
        return debugfs;

    if ((fp = fopen("/proc/mounts", "r")) == NULL)
        return NULL;

    while (fscanf(fp, "%*s %" STR(PATH) "s %99s %*s %*d %*d\n",
                    debugfs, type) == 2) {
        if (strcmp(type, "debugfs") == 0)
            break;
    }
    fclose(fp);

    if (strcmp(type, "debugfs") != 0)
        return NULL;

    debugfs_found = 1;
    return debugfs;
}

static int trace_write(int fd, const char *fmt, ...)
{
    va_list ap;
    char buf[256];
    char *pbuf = buf;
    int len, ret = -1;

    if (fd < 0 || !fmt)
        return ret;

    va_start(ap, fmt);
    len = vsnprintf(buf, 256, fmt, ap);
    va_end(ap);

    while (len != 0 && (ret = write(fd, pbuf, len)) != 0) {
        if (ret == -1) {
            if (errno == EINTR)
                continue;
            prerr("%s\n", strerror(errno));
            break;
        }
        len -= ret;
        pbuf += ret;
    }
    return ret;
}

int main(int arg, char **argv)
{
    const char *debugfs;
    char path[PATH + 1];
    int tty_fd, tr_on_fd, marker_fd, tracer_fd;

    debugfs = find_debugfs();
    if (!debugfs) {
        prerr("find_debugfs failed!\n");
        exit(EXIT_FAILURE);
    }

    /* eh-hem, this is permissible for demo code 
     * do not use "system(3)" in production code */
    system("sysctl kernel.ftrace_enabled=1");
    #ifdef TRACE_PID
    {
        pid_t pid = getpid();
        memset(path, 0, PATH + 1);
        snprintf(path, PATH + 1, "echo %d > %s/tracing/set_ftrace_pid", pid,
             debugfs);
        system(path);
    }
    #endif

    /* get "${debugfs}/tracing/current_tracer" file desc. */
    memset(path, 0, PATH + 1);
    strcpy(path, debugfs);
    strcat(path, "/tracing/current_tracer");
    if ((tracer_fd = open(path, O_WRONLY)) < 0) {
        prerr("%s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    /* get "${debugfs}/tracing/tracing_on" file desc. */
    memset(path, 0, PATH + 1);
    strcpy(path, debugfs);
    strcat(path, "/tracing/tracing_on");
    if ((tr_on_fd = open(path, O_WRONLY)) < 0) {
        prerr("%s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    /* get "${debugfs}/tracing/trace_marker" file desc. */
    memset(path, 0, PATH + 1);
    strcpy(path, debugfs);
    strcat(path, "/tracing/trace_marker");
    if ((marker_fd = open(path, O_WRONLY)) < 0) {
        prerr("%s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    /* get "/dev/tty1" file desc. */
    if ((tty_fd = open("/dev/tty1", O_WRONLY)) < 0) {
        prerr("%s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    /* clear any previous trace */
    if ((trace_write(tr_on_fd, "0") < 0) ||
            (trace_write(tracer_fd, "nop") < 0)) {
        prerr("trace_write failed!\n");
        exit(EXIT_FAILURE);
    }

    /* "echo function_graph > ${debugfs}/tracing/current_tracer" */
    if (trace_write(tracer_fd, "function_graph") < 0) {
        prerr("trace_write failed!\n");
        exit(EXIT_FAILURE);
    }

    /* "echo 1 > ${debugfs}/tracing/tracing_on" */
    if (trace_write(tr_on_fd, "1") < 0) {
        prerr("trace_write failed!\n");
        exit(EXIT_FAILURE);
    }

    /* finally, perform the trace */
    if (trace_write(marker_fd, "Before console write\n") < 0) {
        prerr("trace_write failed!\n");
        exit(EXIT_FAILURE);
    }

    if (trace_write(tty_fd, "Dunia, vipi?\n") < 0) {
        prerr("trace_write failed!\n");
        exit(EXIT_FAILURE);
    }

    if (trace_write(marker_fd, "After console write\n") < 0) {
        prerr("trace_write failed!\n");
        exit(EXIT_FAILURE);
    }

    /* "echo 0 > ${debugfs}/tracing/tracing_on" */
    if (trace_write(tr_on_fd, "0") < 0) {
        prerr("trace_write failed!\n");
        exit(EXIT_FAILURE);
    }

    /* "lazy" copying the trace output to pwd */
    {
        memset(path, 0, PATH + 1);
        snprintf(path, PATH + 1,
             "cat %s/tracing/trace > ftrace_output.txt", debugfs);
        system(path);
    }

    /* clear the ring buffer */
    if (trace_write(tracer_fd, "nop") < 0) {
        prerr("trace_write failed!\n");
        exit(EXIT_FAILURE);
    }

    #ifdef TRACE_PID
    /* "lazy" reset "set_ftrace_pid" */
    {
        memset(path, 0, PATH + 1);
        snprintf(path, PATH + 1, "echo > %s/tracing/set_ftrace_pid",
             debugfs);
        system(path);
    }
    #endif

    close(tty_fd);
    close(tr_on_fd);
    close(marker_fd);
    close(tracer_fd);
    exit(EXIT_SUCCESS);
}

Wednesday, 29 April 2015

WorkQueue mechanism in Linux

1.Work Queue

The Linux Workqueue mechanism is to simplify the creation of kernel threads. By calling workqueue interface you can create kernel threads. And it may be based on the current number of system CPU to create the number of threads so that the transaction can be parallelized thread. work queue is the kernel simple and effective mechanism, he apparently simplifies the creation of the kernel daemon facilitate the programming of the user.

Work Queue (work queue) is in the form of work after another push executed after the work queue can push the work, referred to a kernel thread to perform, that is, the lower half can be executed in the process context. The most important thing is the work queue is allowed to reschedule or even sleep.


2.Data Structure
We pushed back the implementation of the task called work , describing its data structure work_struct,

struct work_struct {
    atomic_long_t data;      / * Work handler func parameter * /
#define WORK_STRUCT_PENDING 0        /* T if work item pending execution */
#define WORK_STRUCT_STATIC 1        /* static initializer (debugobjects) */
#define WORK_STRUCT_FLAG_MASK (3UL)
#define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)
    struct list_head entry;        /*Connection work pointer*/
    work_func_t func;              /*work handler*/
#ifdef CONFIG_LOCKDEP
    struct lockdep_map lockdep_map;
#endif
};

The work queue structure to organize a work queue (workqueue), its data structure

struct workqueue_struct {
 struct cpu_workqueue_struct *cpu_wq;
 struct list_head list;
 const char *name;   /*workqueue name*/
 int singlethread;   / * Is not a single thread - threaded our preferred first CPU -0 indicates the default worker thread event*/
 int freezeable;  /* Freeze threads during suspend */
 int rt;
}; 

If it is multi-threaded, Linux CPU number of the current system to create its structure is based on cpu_workqueue_struct,
struct cpu_workqueue_struct {
 spinlock_t lock;
 struct list_head worklist;
 wait_queue_head_t more_work;
 struct work_struct *current_work; 
 struct workqueue_struct *wq;  
 struct task_struct *thread; 
} ____cacheline_aligned;



In the structure of the main maintains a job queue, and kernel threads need to sleep waiting queue, and also maintains a task context, the task_struct.
The relationship between the three is as follows:

Creating work
3.1 Creating job queue
a. create_singlethread_workqueue (name)
Implementation mechanism of the function shown below, the function returns a pointer to a variable of type struct workqueue_struct of the pointer variable points to the memory address inside the function call kzalloc dynamically generated. So the driver call void destroy_workqueue (struct workqueue_struct * wq) In the case of the work queue is no longer used to release the memory address here.


Cwq figure is a per-CPU type of address space. For create_singlethread_workqueue terms, even for multi-CPU system, the kernel is responsible for creating a worker_thread only kernel process. After the kernel process is created, it will first define a graph in wait node, and then check cwq worklist in a body of the loop, if the queue is empty, then the node will be added to the wait cwq the more_work then Sleep in the waiting queue.

Driver calls queue_work (struct workqueue_struct * wq, struct work_struct * work) was added to the wq work node. work will in turn increase the cwq-> worklist points list. queue_work to cwq-> worklist added a work node, while calls to awaken dormant wake_up on cwq-> more_work of worker_thread process. wake_up will first wait on the call autoremove_wake_function function node, then the node is removed from the wait cwq-> more_work in.

worker_thread again is scheduled to begin processing cwq-> worklist for all the nodes work ... when all work is completed node processing, worker_thread again will wait node to cwq-> more_work, then dormant in the waiting queue until Driver call queue_work again ...

b. create_workqueue



With respect create_singlethread_workqueue, create_workqueue wq will also be assigned a job queue, but differs in that for the purposes of multi-CPU system, for each CPU, cwq structure will be created for a per-CPU, which corresponds every cwq, will generate a new worker_thread process. However, when a node to submit work on cwq with queue_work, which CPU calling the function, then the CPU Bianxiang worklist cwq corresponding increase in work on the node.

c. Summary
When the user invokes workqueue initialization interfaces create_workqueue or create_singlethread_workqueue queue for workqueue initialized, the kernel starts the user is assigned a workqueue object and its chain to a global workqueue queue. Then Linux CPU based on the current situation, in order to workqueue object is assigned the same number of CPU cpu_workqueue_struct objects, each cpu_workqueue_struct objects will exist a task queue. Then, Linux cpu_workqueue_struct for each object is assigned a kernel thread, namely the kernel daemon to process each queue tasks. At this point, the user invokes the initialization interface workqueue initialization is complete, return workqueue pointer. After Workqueue initialization is complete, the task run context to build up, but not yet perform specific tasks, therefore, need to define specific work_struct object. Then work_struct added to the job queue, Linux daemon wakes up to handle the task.

 Workqueue kernel implementation of the principles described above can be described as follows:




3.2 Creating work
To use the job queue, the first thing to do is to create some post-needed push to complete the work. The structure can be built statically compiled by DECLARE_WORK:
DECLARE_WORK (name, void (* func) (void *), void * data);
This will create a file called statically name, pending function func, parameter data of work_struct structure.
Similarly, you can create a pointer at runtime by a work:
INIT_WORK (structwork_struct * work, woid (* func) (void *), void * data);


4. Scheduling
a. schedule_work

In most cases, you do not need to create their own job queue, but only defines the work, the work attached to the core structure predefined event scheduler work queue defines a static global amount in kernel / workqueue.c in Work Queue static struct workqueue_struct * keventd_wq; default worker thread is called events / n, where n is the number of processors, each processor corresponds to a thread. For example, single-processor systems only events / 0 of such a thread. The dual-processor system will be more of an events / 1 thread.
Scheduling work structure, work structure will add to the overall work of the event queue keventd_wq, called queue_work common module. Foreign shielded keventd_wq interface, users do not know this parameter is equivalent to using the default parameters. keventd_wq by the kernel to maintain their own, create, destroy. Such work will soon be scheduled once the worker thread in the processor on which it is awakened, it will be executed.

. b schedule_delayed_work (& work, delay);
Sometimes I do not want to work will be executed immediately, but want it to execute again after some delay. In this case, and you can also use the timer to delay the scheduling, after the expiration of a default timer callback registration work. After delay delay, by the timer wake up, will add to the work queue wq work in.

Work is not the priority queue, essentially as a FIFO manner.

Example

#include <linux/module.h>
#include <linux/init.h>
#include <linux/workqueue.h>
static struct workqueue_struct *queue=NULL;
static struct work_struct   work;
staticvoid work_handler(struct work_struct *data)
{
       printk(KERN_ALERT"work handler function.\n");
}
static int __init test_init(void)
{
      queue=create_singlethread_workqueue("hello world");
      if (!queue)
            goto err;
       INIT_WORK(&work,work_handler);
       schedule_work(&work);
      return0;
err:
      return-1;
}
static   void __exit test_exit(void)
{
       destroy_workqueue(queue);
}
MODULE_LICENSE("GPL");
module_init(test_init);
module_exit(test_exit);

The longstanding task queue interface was removed in 2.5.41; in its place is a new "workqueue" mechanism. Workqueues are very similar to task queues, but there are some important differences. Among other things, each workqueue has one or more dedicated worker threads (one per CPU, by default) associated with it. So all tasks running out of workqueues have a process context, and can thus sleep. Note that access to user space is not possible from code running out of a workqueue; there simply is no user space to access. Drivers can create their own work queues - with their own worker threads - but there is a default queue (for each processor) provided by the kernel that will work in most situations.
Workqueues are created with one of:

    struct workqueue_struct *create_workqueue(const char *name);
    struct workqueue_struct *create_singlethread_workqueue(const char *name);

A workqueue created with create_workqueue() will have one worker thread for each CPU on the system;create_singlethread_workqueue(), instead, creates a workqueue with a single worker process. The name of the queue is limited to ten characters; it is only used for generating the "command" for the kernel thread(s) (which can be seen in ps or top).
Tasks to be run out of a workqueue need to be packaged in a struct work_struct structure. This structure may be declared and initialized at compile time as follows:

    DECLARE_WORK(name, void (*function)(void *), void *data);

Here, name is the name of the resulting work_struct structure, function is the function to call to execute the work, and data is a pointer to pass to that function.
To set up a work_struct structure at run time, instead, use the following two macros:

    INIT_WORK(struct work_struct *work, 
              void (*function)(void *), void *data);
    PREPARE_WORK(struct work_struct *work, 
                 void (*function)(void *), void *data);

The difference between the two is that INIT_WORK initializes the linked list pointers within the work_struct structure, while PREPARE_WORKchanges only the function and data pointers. INIT_WORK must be used at least once before queueing the work_struct structure, but shouldnot be used if the work_struct might already be in a workqueue.
Actually queueing a job to be executed is simple:

    int queue_work(struct workqueue_struct *queue, 
                   struct work_struct *work);
    int queue_delayed_work(struct workqueue_struct *queue, 
                    struct work_struct *work,
                           unsigned long delay);

The second form of the call ensures that a minimum delay (in jiffies) passes before the work is actually executed. The return value from both functions is nonzero if the work_struct was actually added to queue (otherwise, it may have already been there and will not be added a second time).
Entries in workqueues are executed at some undefined time in the future, when the associated worker thread is scheduled to run (and after the delay period, if any, has passed). If it is necessary to cancel a delayed task, you can do so with:

    int cancel_delayed_work(struct work_struct *work);

Note that this workqueue entry could actually be executing when cancel_delayed_work() returns; all this function will do is keep it from starting after the call.
To ensure that none of your workqueue entries are running, call:

    void flush_workqueue(struct workqueue_struct *queue);

This would be a good thing to do, for example, in a device driver shutdown routine. Note that if the queue contains work with long delays this call could take a long time to complete. This function will not (as of 2.5.68) wait for any work entries submitted after the call was first made; you should ensure that, for example, any outstanding work queue entries will not resubmit themselves. You should also cancel any delayed entries (with cancel_delayed_work()) first if need be.
Work queues can be destroyed with:

    void destroy_workqueue(struct workqueue_struct *queue);

This operation will flush the queue, then delete it.
Finally, for tasks that do not justify their own workqueue, a "default" work queue (called "events") is defined. work_struct structures can be added to this queue with:

    int schedule_work(struct work_struct *work);
    int schedule_delayed_work(struct work_struct *work, unsigned long delay);

Most users of workqueues can probably use the predefined queue, but one should bear in mind that it is a shared resource. Long delays in the worker function will slow down other users of the queue, and should be avoided. There is a flush_scheduled_work() function which will wait for everything on this queue to be executed. If your module uses the default queue, it should almost certainly callflush_scheduled_work() before allowing itself to be unloaded.


With first call, the work is scheduled immediately and is run as soon as the events worker thread on the current processor wakes up.
While with second call, the work_struct represented by &work will not execute for at least delay timer ticks into the future.


One final note: schedule_work(), schedule_delayed_work() and flush_scheduled_work() are exported to any modules which wish to use them. The other functions (for working with separate workqueues) are exported to GPL-licensed modules only.



Reference
https://lwn.net/Articles/23634/




Saturday, 18 April 2015

UART framwork in Linux


uart linux device driver architecture model of analysis

Introduction
In linux in, serial port terminal is often referred to in the shell, we see / dev / ttyS * is the corresponding serial terminal device nodes. Before analyzing the specific serial driver. It is necessary to analyze uart driven architecture . it is a serial device driver package layers.
Two: uart driver architecture overview
As shown below:




When uart_port receiving data from serial devices, the device will be placed in the corresponding cache line discipline area.
Such user at the time of writing the serial driver, only first to register a uart_driver. Its main role is to define the device node number. Then the operation of packaging equipment will be in uart_port. Drive engineers do not need to be concerned about the upper flow, just by hardware specification uart_port the interface functions can be completed.

Three: uart driver important data structures and their associated
We can consider under their own, based on the above framework code should first consider how to write the following:
1: a uart_driver registration period is usually the device number that corresponds to the user space will see uart_driver multiple device nodes, for example.:
/ dev / ttyS0 / dev / ttyS1 each device node corresponds to a specific hardware architecture point of view from above, each device file should correspond to a uart_port ie:. uart_device how relations with more than one uart_port how to go up? operation is to distinguish which device file?

one for each uart_port -circ_buf, so uart_port must have this relationship up cache

Memories tty driver architecture .tty_driver member points to a call of an array that tty-> ttys. Each device file corresponds to a set array while the array data structure of the code for tty_struct. Corresponding tty_struct will tty_driver and ldisc associate.
That in uart driver, whether it can be used in the same way to deal with it?

The uart drive common data structures expressed as follows:





Combined with the above questions raised can clearly understand the design of these structures.

uart_driver registration operation

Uart_driver registered corresponding function: uart_register_driver () code is as follows:

int uart_register_driver(struct uart_driver *drv)
{
struct
tty_driver *normal = NULL;
int
i, retval;

BUG_ON(drv->state);

/*
*
Maybe we should be using a slab cache for this, especially if
*
we have a large number of ports to handle.
*/
drv->state
= kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
retval
= -ENOMEM;
if
(!drv→state)
goto
out;
normal = alloc_tty_driver(drv->nr);
if (!normal)
 
        goto out;

 
   drv->tty_driver = normal;

 
   normal->owner      = drv->owner;
 
   normal->driver_name    = drv->driver_name;
 
   normal->name       = drv->dev_name;
 
   normal->major      = drv->major;
 
   normal->minor_start    = drv->minor;
 
   normal->type       = TTY_DRIVER_TYPE_SERIAL;
 
   normal->subtype        = SERIAL_TYPE_NORMAL;
 
   normal->init_termios   = tty_std_termios;
 
   normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
 
   normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
 
   normal->flags      = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
 
   normal->driver_state    = drv;
 
   tty_set_operations(normal, &uart_ops);

 
   /*
 
    * Initialise the UART state(s).
 
    */
 
   for (i = 0; i nr; i++) {
 
       struct uart_state *state = drv->state + i;

 
       state->close_delay     = 500;    /* .5 seconds */
 
       state->closing_wait    = 30000;  /* 30 seconds */

 
       mutex_init(&state->mutex);
 
   }

 
   retval = tty_register_driver(normal);
out:
 
   if (retval
 
       put_tty_driver(normal);
 
       kfree(drv->state);
 
   }
 
   return retval;
}

uart_register_driver:

Register a uart driver with the core driver. We in turn register with the tty layer, and initialise the core driver per-port state.
We have a proc file in /proc/tty/driver which is named after the normal driver.
drv->port should be NULL, and the per-port structures should be registered using uart_add_one_port after this call has succeeded.



 int uart_register_driver(struct uart_driver *drv)
 {
         struct tty_driver *normal;
         int i, retval;
 
         BUG_ON(drv->state);
 
         /*
          * Maybe we should be using a slab cache for this, especially if
          * we have a large number of ports to handle.
          */
         drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
         if (!drv->state)
                 goto out;
 
         normal = alloc_tty_driver(drv->nr);
         if (!normal)
                 goto out_kfree;
 
         drv->tty_driver = normal;
 
        normal->driver_name     = drv->driver_name;
       normal->name            = drv->dev_name;
         normal->major           = drv->major;
         normal->minor_start     = drv->minor;
         normal->type            = TTY_DRIVER_TYPE_SERIAL;
         normal->subtype         = SERIAL_TYPE_NORMAL;
         normal->init_termios    = tty_std_termios;
         normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
         normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
         normal->flags           = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
         normal->driver_state    = drv;
         tty_set_operations(normal, &uart_ops);
 
         /*
          * Initialise the UART state(s).
          */
         for (i = 0; i < drv->nr; i++) {
                 struct uart_state *state = drv->state + i;
                 struct tty_port *port = &state->port;
 
                 tty_port_init(port);
                 port->ops = &uart_port_ops;
         }
 
         retval = tty_register_driver(normal);
         if (retval >= 0)
                 return retval;
 
         for (i = 0; i < drv->nr; i++)
                 tty_port_destroy(&drv->state[i].port);
         put_tty_driver(normal);
 out_kfree:
         kfree(drv->state);
 out:
         return -ENOMEM;
 }
 /**
  *      uart_unregister_driver - remove a driver from the uart core layer
  *      @drv: low level driver structure
  *
  *      Remove all references to a driver from the core driver.  The low
  *      level driver must have removed all its ports via the
  *      uart_remove_one_port() if it registered them with uart_add_one_port().
  *      (ie, drv->port == NULL)
  */
 void uart_unregister_driver(struct uart_driver *drv)
 {
         struct tty_driver *p = drv->tty_driver;
         unsigned int i;
 
         tty_unregister_driver(p);
         put_tty_driver(p);
         for (i = 0; i < drv->nr; i++)
                 tty_port_destroy(&drv->state[i].port);
         kfree(drv->state);
         drv->state = NULL;
         drv->tty_driver = NULL;
442 }
    uart_add_one_port() operations

 /**
  *      uart_add_one_port - attach a driver-defined port structure
  *      @drv: pointer to the uart low level driver structure for this port
  *      @uport: uart port structure to use for this port.
  *
  *      This allows the driver to register its own uart_port structure
  *      with the core driver.  The main purpose is to allow the low
  *      level uart drivers to expand uart_port, rather than having yet
  *      more levels of structures.
  */
 int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
 {
         struct uart_state *state;
         struct tty_port *port;
         int ret = 0;
         struct device *tty_dev;
         int num_groups;
         BUG_ON(in_interrupt());
 
         if (uport->line >= drv->nr)
                 return -EINVAL;
 
         state = drv->state + uport->line;
         port = &state->port;
 
         mutex_lock(&port_mutex);
         mutex_lock(&port->mutex);
         if (state->uart_port) {
                 ret = -EINVAL;
                 goto out;
         }
 
         /* Link the port to the driver state table and vice versa */
         state->uart_port = uport;
         uport->state = state;
 
         state->pm_state = UART_PM_STATE_UNDEFINED;
         uport->cons = drv->cons;
 
         /*
          * If this port is a console, then the spinlock is already
          * initialised.
          */
         if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
                 spin_lock_init(&uport->lock);
                 lockdep_set_class(&uport->lock, &port_lock_key);
        }
         if (uport->cons && uport->dev)
                 of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
 
         uart_configure_port(drv, state, uport);
 
         num_groups = 2;
         if (uport->attr_group)
                 num_groups++;
 
         uport->tty_groups = kcalloc(num_groups, sizeof(*uport->tty_groups),
                                     GFP_KERNEL);
         if (!uport->tty_groups) {
                 ret = -ENOMEM;
                 goto out;
         }
         uport->tty_groups[0] = &tty_dev_attr_group;
         if (uport->attr_group)
                 uport->tty_groups[1] = uport->attr_group;
 
         /*
          * Register the port whether it's detected or not.  This allows
          * setserial to be used to alter this port's parameters.
          */
         tty_dev = tty_port_register_device_attr(port, drv->tty_driver,
                         uport->line, uport->dev, port, uport->tty_groups);
         if (likely(!IS_ERR(tty_dev))) {
                 device_set_wakeup_capable(tty_dev, 1);
         } else {
                 dev_err(uport->dev, "Cannot register tty device on line %d\n",
                        uport->line);
         }
 
         /*
          * Ensure UPF_DEAD is not set.
          */
         uport->flags &= ~UPF_DEAD;
 
  out:
         mutex_unlock(&port->mutex);
         mutex_unlock(&port_mutex);
 
         return ret;
 }


/**
  *      uart_remove_one_port - detach a driver defined port structure
  *      @drv: pointer to the uart low level driver structure for this port
*      @uport: uart port structure for this port
  *
  *      This unhooks (and hangs up) the specified port structure from the
  *      core driver.  No further calls will be made to the low-level code
  *      for this port.
  */
 int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
 {
         struct uart_state *state = drv->state + uport->line;
         struct tty_port *port = &state->port;
         struct tty_struct *tty;
         int ret = 0;
 
         BUG_ON(in_interrupt());
 
         if (state->uart_port != uport)
                 dev_alert(uport->dev, "Removing wrong port: %p != %p\n",
                         state->uart_port, uport);
 
         mutex_lock(&port_mutex);
 
         /*
          * Mark the port "dead" - this prevents any opens from
          * succeeding while we shut down the port.
          */
         mutex_lock(&port->mutex);
         if (!state->uart_port) {
                 mutex_unlock(&port->mutex);
                 ret = -EINVAL;
                 goto out;
         }
         uport->flags |= UPF_DEAD;
         mutex_unlock(&port->mutex);
 
         /*
          * Remove the devices from the tty layer
          */
         tty_unregister_device(drv->tty_driver, uport->line);
 
         tty = tty_port_tty_get(port);
         if (tty) {
                 tty_vhangup(port->tty);
                 tty_kref_put(tty);
         }
 
         /*
          * If the port is used as a console, unregister it
         */
         if (uart_console(uport))
                 unregister_console(uport->cons);
 
         /*
          * Free the port IO and memory resources, if any.
          */
         if (uport->type != PORT_UNKNOWN)
                 uport->ops->release_port(uport);
         kfree(uport->tty_groups);
 
         /*
          * Indicate that there isn't a port here anymore.
          */
         uport->type = PORT_UNKNOWN;
 
         state->uart_port = NULL;
 out:
         mutex_unlock(&port_mutex);
 
         return ret;
 }
First, this function can not be used. Uart_port-> line is to uart device file number in interrupt context. It is the corresponding uart_driver-> state array uart_port-> line items.
It is mainly the corresponding initialization uart_driver-> state items. Then call uart_configure_port () to automatically configure the port and then registered tty_device. If the user space to run the udev or has been configured hotplug. Will automatically generate device files in / dev up.
Operational flowchart is as follows:
 
 static const struct tty_operations uart_ops = {
         .open           = uart_open,
         .close          = uart_close,
         .write          = uart_write,
         .put_char       = uart_put_char,
         .flush_chars    = uart_flush_chars,
         .write_room     = uart_write_room,
         .chars_in_buffer= uart_chars_in_buffer,
         .flush_buffer   = uart_flush_buffer,
         .ioctl          = uart_ioctl,
         .throttle       = uart_throttle,
         .unthrottle     = uart_unthrottle,
         .send_xchar     = uart_send_xchar,
         .set_termios    = uart_set_termios,
         .set_ldisc      = uart_set_ldisc,
         .stop           = uart_stop,
         .start          = uart_start,
         .hangup         = uart_hangup,
         .break_ctl      = uart_break_ctl,
         .wait_until_sent= uart_wait_until_sent,
 #ifdef CONFIG_PROC_FS
         .proc_fops      = &uart_proc_fops,
 #endif
         .tiocmget       = uart_tiocmget,
         .tiocmset       = uart_tiocmset,
         .get_icount     = uart_get_icount,
 #ifdef CONFIG_CONSOLE_POLL
         .poll_init      = uart_poll_init,
         .poll_get_char  = uart_poll_get_char,
         .poll_put_char  = uart_poll_put_char,
 #endif
 };
 
open operating device node
When users open space to perform the operation, it will perform uart_ops-> open Uart_ops definition as follows:

 /*
  * Calls to uart_open are serialised by the tty_lock in
  *   drivers/tty/tty_io.c:tty_open()
  * Note that if this fails, then uart_close() _will_ be called.
  *
  * In time, we want to scrap the "opening nonpresent ports"
  * behaviour and implement an alternative way for setserial
  * to set base addresses/ports/types.  This will allow us to
  * get rid of a certain amount of extra tests.
  */
 static int uart_open(struct tty_struct *tty, struct file *filp)
 {
         struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_tate;
         int retval, line = tty->index;
         struct uart_state *state = drv->state + line;
         struct tty_port *port = &state->port;
 
         pr_debug("uart_open(%d) called\n", line);
 
         spin_lock_irq(&port->lock);
         ++port->count;
         spin_unlock_irq(&port->lock);
 
         /*
          * We take the semaphore here to guarantee that we won't be re-entered
          * while allocating the state structure, or while we request any IRQ         * that the driver may need.  This also has the nice side-effect tha         * it delays the action of uart_hangup, so we can guarantee that
          * state->port.tty will always contain something reasonable.
          */
         if (mutex_lock_interruptible(&port->mutex)) {
                 retval = -ERESTARTSYS;
                 goto end;
         }
 
         if (!state->uart_port || state->uart_port->flags & UPF_DEAD) {
                 retval = -ENXIO;
                goto err_unlock;
         }
 
         tty->driver_data = state;
         state->uart_port->state = state;
         state->port.low_latency =
                 (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0;
         tty_port_tty_set(port, tty);
 
         /*
          * Start up the serial port.
          */
         retval = uart_startup(tty, state, 0);
 
         /*
          * If we succeeded, wait until the port is ready.
          */
         mutex_unlock(&port->mutex);
         if (retval == 0)
                 retval = tty_port_block_til_ready(port, tty, filp);
 
 end:
         return retval;
 err_unlock:
         mutex_unlock(&port->mutex);
         goto end;
 }

Here, Note To complete the ring buffer that info-> xmit initialization. Then call the port-> ops-> startup () will bring the port to a working state. Other is an adjustable parameter settings, do not explained in detail.

device node write operation
Write operation corresponds to the operation of the interface for uart_write () code is as follows:

 static int uart_write(struct tty_struct *tty,
                                         const unsigned char *buf, int count)
 {
         struct uart_state *state = tty->driver_data;
         struct uart_port *port;
         struct circ_buf *circ;
         unsigned long flags;
         int c, ret = 0;
 
         /*
          * This means you called this function _after_ the port was
          * closed.  No cookie for you.
          */
         if (!state) {
                 WARN_ON(1);
                 return -EL3HLT;
         }
 
         port = state->uart_port;
        circ = &state->xmit;
 
         if (!circ->buf)
                 return 0;
 
         spin_lock_irqsave(&port->lock, flags);
         while (1) {
                 c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
                 if (count < c)
                         c = count;
                 if (c <= 0)
                         break;
                 memcpy(circ->buf + circ->head, buf, c);
                 circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
                 buf += c;
                 count -= c;
                 ret += c;
         }
 
         __uart_start(tty);
         spin_unlock_irqrestore(&port->lock, flags);
 
         return ret;
 }
static void uart_start(struct tty_struct *tty)
{
 
   struct uart_state *state = tty->driver_data;
 
   struct uart_port *port = state->port;
 
   unsigned long flags;

 
   spin_lock_irqsave(&port->lock, flags);
 
   __uart_start(tty);
 
   spin_unlock_irqrestore(&port->lock, flags);
}

static void __uart_start(struct tty_struct *tty)
{
 
   struct uart_state *state = tty->driver_data;
 
   struct uart_port *port = state->port;

 
   if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf &&
 
       !tty->stopped && !tty->hw_stopped)
 
       port->ops->start_tx(port);
}

Note:
As can be seen from the code here note if the operation is to initialize the state-> info. Note port-> info is state-> a copy of the info. That port directly through port-> info can be found in the cache it is to operate.
 /*
  * Startup the port.  This will be called once per open.  All calls
  * will be serialised by the per-port mutex.
  */
 static int uart_port_startup(struct tty_struct *tty, struct uart_state *state                 int init_hw)
 {
         struct uart_port *uport = state->uart_port;
         unsigned long page;
         int retval = 0;
 
         if (uport->type == PORT_UNKNOWN)
                 return 1;
 
         /*
          * Make sure the device is in D0 state.
          */
         uart_change_pm(state, UART_PM_STATE_ON);
 
         /*
          * Initialise and allocate the transmit and temporary
          * buffer.
          */
         if (!state->xmit.buf) {
                 /* This is protected by the per port mutex */
                 page = get_zeroed_page(GFP_KERNEL);
                 if (!page)
                         return -ENOMEM;
 
                 state->xmit.buf = (unsigned char *) page;
                 uart_circ_clear(&state->xmit);
         }
 
         retval = uport->ops->startup(uport);
         if (retval == 0) {
                 if (uart_console(uport) && uport->cons->cflag) {
                         tty->termios.c_cflag = uport->cons->cflag;
                         uport->cons->cflag = 0;
                 }
                 /*
                  * Initialise the hardware port settings.
                  */
                 uart_change_speed(tty, state, NULL);
 
                 if (init_hw) {
                         /*
                          * Setup the RTS and DTR signals once the
                          * port is open and ready to respond.
                          */
                         if (tty->termios.c_cflag & CBAUD)
                                 uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
                 }
 
                 spin_lock_irq(&uport->lock);
                 if (uart_cts_enabled(uport) &&
                     !(uport->ops->get_mctrl(uport) & TIOCM_CTS))
                         uport->hw_stopped = 1;
                 else
                         uport->hw_stopped = 0;
                 spin_unlock_irq(&uport->lock);
         }
 
         /*
          * This is to allow setserial on this port. People may want to set
          * port/irq/type and then reconfigure the port properly if it failed
          * now.
          */
         if (retval && capable(CAP_SYS_ADMIN))
                 return 1;
 
         return retval;
 }
 
 static int uart_startup(struct tty_struct *tty, struct uart_state *state,
                 int init_hw)
 {
         struct tty_port *port = &state->port;
         int retval;
 
         if (port->flags & ASYNC_INITIALIZED)
                 return 0;
 
         /*
          * Set the TTY IO error marker - we will only clear this
          * once we have successfully opened the port.
          */
         set_bit(TTY_IO_ERROR, &tty->flags);
 
         retval = uart_port_startup(tty, state, init_hw);
         if (!retval) {
                 set_bit(ASYNCB_INITIALIZED, &port->flags);
                 clear_bit(TTY_IO_ERROR, &tty->flags);
         } else if (retval > 0)
                 retval = 0;
 
        return retval;
 }
 
In this function, the continued operation of the device to complete the initialization file corresponding state. Now open the device the user space. That is to be operated on this file. It uart_port also began to work. That call uart_startup () make it into work state. of course, you need to initialize the corresponding ring buffer uart_port circ_buf. that state-> info-> xmit.

Pay particular attention to where the tty-> driver_data = state; this is because after only port-related operations, do not need to understand uart_driver information.
Tracking a look at two important subroutine which calls uart_get () and uart_startup () first analyze uart_get () code is as follows...:

static struct uart_state *uart_get (struct uart_driver *drv, int line)
{
 
   struct uart_state *state;
 
   int ret = 0;

 
   state = drv->state + line;
 
   if (mutex_lock_interruptible(&state->mutex)) {
 
       ret = -ERESTARTSYS;
 
       goto err;
 
   }

 
   state->count++;
 
   if (!state->port || state->port->flags & UPF_DEAD) {
 
       ret = -ENXIO;
 
       goto err_unlock;
 
   }

 
   if (!state->info) {
 
       state->info = kzalloc(sizeof(struct uart_info), GFP_KERNEL);
 
       if (state->info) {
 
            init_waitqueue_head(&state->info->open_wait);
 
            init_waitqueue_head(&state->info->delta_msr_wait);

 
            /*
 
             * Link the info into the other structures.
 
             */
 
            state->port->info = state->info;

 
            tasklet_init(&state->info->tlet, uart_tasklet_action,
 
                      (unsigned long)state);
 
       } else {
 
            ret = -ENOMEM;
 
            goto err_unlock;
 
       }
 
   }
 
   return state;

err_unlock:
 
   state->count--;
 
   mutex_unlock(&state->mutex);
err:
 
   return ERR_PTR(ret);

}

UART In BeagleBone Black:


                   RX TX           CTS   RTS                        Device      Remark
 UART0 J1_4 J1_5                               /dev/ttyO0      BeagleBone Black only
 UART1 P9_26 P9_24 P9_20 P9_19               /dev/ttyO1
 UART2 P9_22 P9_21 P8_37 P8_38               /dev/ttyO2
 UART3          P9_42 P8_36 P8_34               /dev/ttyO3      TX only
 UART4 P9_11 P9_13 P8_35 P8_33               /dev/ttyO4
 UART5 P8_38 P8_37 P8_31 P8_32               /dev/ttyO5


Device tree would be having different name for these so look into the base address and identify UARTs and then change them.  


Summary
After this section is to analyze the serial-driven basis in the understanding of the tty driver architecture, come to understand uart driver architecture should not be difficult. With our in-depth analysis in linux device driver, more deeply appreciate, linux device driver architecture many of which are interlinked. As long as a deep understanding of a driver architecture. replicability. it is easy to analyze the drivers of other architectures.

Reference
1)Essential Linux Device driver chapter 6
2)serial drivers PPT by free-electrons

For any query post a comment 

Thank You Enjoy !!!!