Friday, October 17, 2014

GIT

scp -p -P 29418 -i D:/id_rsa xxx@10.10.11.221:hooks/commit-msg .git/hooks/
git add test.txt
git commit -m "Test change"

git clean -fdx

git push http://10.10.11.221/gerrit/info3low/pf/ipc HEAD:refs/for/master

info3-low_dev

git status

$ git commit --signoff -m "Added driver for RT Domain Shared memory"

$ git format-patch -1

To Rever changes
------
http://gitimmersion.com/lab_16.html
$ git revert HEAD --no-edit
[master 0c7524c] Revert "Oops, we didn't want this commit"
 1 file changed, 1 insertion(+), 1 deletion(-)

----

http://linux.die.net/man/1/git-format-patch
https://www.kernel.org/pub/software/scm/git/docs/git-format-patch.html
https://openhatch.org/wiki/How_to_generate_patches_with_git_format-patch

Cloning into 'kernel'...
remote: Counting objects: 3094776, done
remote: Finding sources: 100% (3094776/3094776)
remote: Total 3094776 (delta 2600981), reused 3094776 (delta 2600981)
Receiving objects: 100% (3094776/3094776), 641.04 MiB | 639.00 KiB/s, done.
Resolving deltas: 100% (2600981/2600981), done.
Checking connectivity... done.
error: unable to create file drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c (No s
uch file or directory)
Checking out files: 100% (43492/43492), done.
fatal: unable to checkout working tree
warning: Clone succeeded, but checkout failed.
You can inspect what was checked out with 'git status'
and retry the checkout with 'git checkout -f HEAD'

curl -o .git/hooks/commit-msg xxx@10.10.11.221/tools/hooks/commit-msg
chmod u+x .git/hooks/commit-msg

-----
scp -p -P 29418 xxx@10.10.11.221:hooks/commit-msg .git/hooks/

git clone http://10.10.11.221/gerrit/info3low/pf/ipc
git checkout mule114
git pull http://10.10.11.221/gerrit/info3low/pf/ipc mule114

git rm test.txt
git add iccom_app_lib/
git push http://10.10.11.221/gerrit/info3low/pf/ipc HEAD:refs/for/mule114
git commit --amend

$ scp -p -P 29418 john.doe@review.example.com:hooks/commit-msg .git/hooks/

-------------------------- Tag -------------------------

$ git tag v1_0

$ git push origin v1_0

xxx@L-3611 /d/GIT/Tag_check/ipc (master)
$ git tag -l
v1_0

$ git checkout v1_1

$ git checkout v1_1^
-----------------------------------

$ diff -uNr linux.vanilla linux.new > patchfile

$ lsdiff patchfile
$cd 
$patch -p1 < ../patchfile
http://clubjuggler.livejournal.com/138364.html
http://mmc.geofisica.unam.mx/acl/edp/Herramientas/CyC++/Documentacion/CyC++Style/industrial-strengthC++.pdf

Friday, September 26, 2014

Dump program

#include
#include

#include "rtds_memory_user.h"

int main(int argc, char *argv[])
{
unsigned int *addr, *paddr, offset;
        int i, j, k, c, count;
unsigned int mapaddr;

if (argc != 3)
{
printf("wrong arguments\n");
return 0;
}

sscanf(argv[1], "%x", &mapaddr);
// mapaddr = strtol(argv[1], NULL, 16);
offset = (mapaddr & 0xFFF)/4;
mapaddr = mapaddr & 0xFFFFF000;
count = atoi(argv[2]);

    addr = (unsigned int*)map_shm_addr(mapaddr);
    if(addr == NULL)
    {
        printf("error in getting shared memory address\n");
        return -1;
    }
    addr += offset;
    paddr = (unsigned int*)mapaddr + offset;

   k = (count+3)/4;
   for(i = 0; i < k; i++)
   {
printf("%X: ",(unsigned int)paddr);
c = (count < 4) ? count : 4;
for (j = 0; j < c; j++)
printf("%X ", *(addr + j));
printf("\n");
addr += 4;
paddr += 4;
        count -= 4;
    }
    return 0;
}

Saturday, August 23, 2014

close() called when process terminated after opening driver

Application is never allowed to crash the kernel if the driver does its job correctly. Otherwise, it is a buggy driver or trash kernel. So, application is not allowed to keep holes in kernel or resources leaked. It is job of the driver to find the resources and holes kept by application and remove it in close().

sample program for simple driver and simple application to prove this.

1) First install headers

# apt-get install build-essential linux-headers-$(uname -r)
2) The following is simple kernel driver in module sample_close.c.

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

MODULE_LICENSE("GPL");
MODULE_AUTHOR("CollegeBoy");
MODULE_DESCRIPTION("A Crash app module");

/*** define ***/
#define SAMPLE_DRIVER_NAME "sample"
#define SAMPLE_DEVICE_ID  "sample_int"

/**** prototype ****/
static int  sample_open(struct inode*, struct file*);
static int  sample_close(struct inode*, struct file*);

static struct miscdevice g_sample_device; /* device driver information */

/******************************************************************************/
/* Function   : sample_open                                                    */
/* Description: open SAMPLE driver                                             */
/******************************************************************************/
static
int sample_open(
 struct inode *inode,
 struct file  *fp
)
{

 printk(KERN_ERR "Device opened!\n");

 return 0;
}

/******************************************************************************/
/* Function   : sample_close                                                   */
/* Description: close SAMPLE driver                                            */
/******************************************************************************/
static
int sample_close(
 struct inode *inode,
 struct file  *fp
)
{
 printk(KERN_ERR "Device Closed!\n");
 return 0;
}

/* initialize file_operations */
static struct file_operations g_sample_fops = {
 .owner   = THIS_MODULE,
 .open   = sample_open,
 .release  = sample_close,
};

static int __init hello_init(void)
{
 int    ret;

 printk(KERN_ERR "Module Init!\n");

 g_sample_device.name  = SAMPLE_DRIVER_NAME;
 g_sample_device.fops  = &g_sample_fops;
 g_sample_device.minor = MISC_DYNAMIC_MINOR;

 /* register device driver */
 ret = misc_register(&g_sample_device);
 if (0 != ret) {
  printk(KERN_ERR "[SAMPLEK]ERR| misc_register failed ret[%d]\n", ret);
  return -1;
 }

 return 0;
}

static void __exit hello_cleanup(void)
{
 int ret;

 printk(KERN_ERR "Module Exit!\n");

 /* unregister device driver */
 ret = misc_deregister(&g_sample_device);
 if (0 != ret) {
  printk(KERN_ERR "[SAMPLEK]ERR| misc_deregister failed ret[%d]\n", ret);
 }
}

module_init(hello_init);
module_exit(hello_cleanup);

3) Copy into Makefile

ifeq ($(KERNELRELEASE),)  

KERNELDIR ?= /lib/modules/$(shell uname -r)/build 
PWD := $(shell pwd)  

.PHONY: build clean  

build:
 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules  

clean:
 rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c 
else  

$(info Building with KERNELRELEASE = ${KERNELRELEASE}) 
obj-m :=    sample_close.o  

endif

4) Do make

root@ubuntu:/mnt/hgfs/UShared/module# make
make -C /lib/modules/3.2.0-23-generic-pae/build  M=/mnt/hgfs/UShared/module   modules  
make[1]: Entering directory `/usr/src/linux-headers-3.2.0-23-generic-pae'
Building with KERNELRELEASE = 3.2.0-23-generic-pae
  CC [M]  /mnt/hgfs/UShared/module/sample_close.o
  Building modules, stage 2.
Building with KERNELRELEASE = 3.2.0-23-generic-pae
  MODPOST 1 modules
  CC      /mnt/hgfs/UShared/module/sample_close.mod.o
  LD [M]  /mnt/hgfs/UShared/module/sample_close.ko
make[1]: Leaving directory `/usr/src/linux-headers-3.2.0-23-generic-pae'

5) insmod 

root@ubuntu:/mnt/hgfs/UShared/module# insmod sample_close.ko 
root@ubuntu:/mnt/hgfs/UShared/module# dmesg -c
[ 3883.685179] Module Init!
6) Application to open driver and to crash itself.

#include 
#include 
#include 
#include 
#include 
#include 
#include 


#define ICCOM_DEV "/dev/iccom"

int main(){

int fd;

 /* open ICCOM driver */
 fd = open(ICCOM_DEV, O_RDWR);
 if (fd < 0) {
  printf("[ICCOM]ERR| handle->fd[%d]\n", fd);
  return -1;
 }
 *((unsigned int *)0) = 87;

}
7) Sample application main.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 


#define SAMPLE_DEV "/dev/sample"

int main(){

int fd;

 /* open SAMPLE driver */
 fd = open(SAMPLE_DEV, O_RDWR);
 if (fd < 0) {
  printf("[SAMPLE]ERR| handle->fd[%d]\n", fd);
  return -1;
 }
 *((unsigned int *)0) = 87;

}
8) Compile, execute, and see dmesg

root@ubuntu:/mnt/hgfs/UShared/module/app# cc main.c 
root@ubuntu:/mnt/hgfs/UShared/module/app# ./a.out 
Segmentation fault (core dumped)
root@ubuntu:/mnt/hgfs/UShared/module/app# dmesg -c
[ 4094.987003] Device opened!
[ 4094.987028] a.out[7653]: segfault at 0 ip 0804845d sp bf96a100 error 6 in a.out[8048000+1000]
[ 4095.103149] Device Closed!
See the device is closed (means, close() function of driver is called by kernel) automatically when the application that opened the driver has crashed. So, your job needs to be remember the current->tgid of the process that is opening the driver in the open() function through fp->private_data. When close function is called, get tgid from the fp->private_data release all the resources and requests raised by the tgid.

Saturday, May 17, 2014

SH-4A Memory map

It is very confusing to read the Renesas SuperH architecture user's manual in English version about MMU and memory map of SH-4A. They confuse the address translation and virtual address. They call 0x80000000 ~ 0xbfffffff as virtual address though the address translation does not happen for this address space even if you enable the MMU. I consider these are not virtual addresses but just shadow memory space or memory window which reflects other physical address space. In legacy devices, it just reflected the physical address space of just removing the MSB 3 bits, in other words, 0x80000000 ~ 0x9fffffff reflects the physical space of 0x00000000 ~ 0x1fffffff. Same way, 0xa0000000 ~ 0xbfffffff too reflected the same physical space of 0x00000000 ~ 0x1fffffff with the exception that this window is non-cacheable and the previous one is cacheable. In recent devices such as SH-4A, the physical address space is extended to the 32 bit and the window can be configured to reflect different physical address space through configuring PMB (Privileged Space Mapping Buffer). And note that the cache attributes too become configurable for these memory windows through the PMB.

SuperH architecture does not provide flat and free physical as well as virtual address space. In each it has reserved areas for the architecture specific definitions. For example, it has reserved 0x1c000000 ~ 0x1fffffff (called area7) addresses in physical address space for the architecture specific control registers. Also, it has reserved 0xfc000000 ~ 0xffffffff to shadow the same registers. Similarly, it has reserved some other areas too. We will see those areas in below sections. The virtual address space also is not flat and only some fixed address ranges are a
vailable. 0x00000000 ~ 0x7fffffff, 0xc0000000 ~ 0xdfffffff are the only the two available virtual memory address spaces. Other areas are not available for MMU translation and they just reflect some fixed memory contents over physical address space.

Legacy Physical address space:

Legacy SuperH architecture allows only less than 512 MB of physical address space with the 29 bit address bus. This address space is mostly shadowed in other regions such as P1 (0x80000000 ~ 0x9fffffff), P2 (0xa0000000 ~ 0xbfffffff) and P4 (0xfc000000 ~ 0xffffffff).


Recent Physical space:
In recent devices such as SH-4A, the address bus is extended to 32 bits.

A more detailed one. You can connect devices in all over the 32 bit physical space except the SH reserved space. But, it does not mean that you can directly access your devices with the physical address it has been connected. Two areas 0x80000000 ~ 0x9fffffff and 0xa0000000 ~ 0xbfffffff needs to be mapped explicitly through PMB. See the detailed picture below:
Other short descriptions about each area:

P0, U0:

It spans in around 2GB (0x00000000 ~ 0x7fffffff) of address space. When MMU is enabled, it becomes the largest virtual address space. The underlying the Physical addresses on this area are shadowed in different areas. So, this virtual address space can be mapped one to one with physical address space or in other way.

P1, P2:

These are memory windows for the privileged mode to access different physical address spaces.
These addresses are not translated through TLB. But, the different physical address spaces can be mapped through PMB in recent devices. In legacy device, just reflect the physical corresponding to the 3 MSBs with 0 value.

P3:

This is the only address space where virtual mapping also can be done as well as the connected devices can be accessed directly with the same physical addresses as they are mapped.

P4:

This will have different view on User mode and Privileged mode. In user mode, it give access to On chip RAM (cache)  and store queues. But, in privileged mode, it gives access to TLBs, PMB, Control registers, etc. But, this area is completely reserved for the architecture.

Overall interesting picture from ARM:

Write buffers vs Store queues

Write Buffers:

Do you know NCM? It is just accumulating the data and sending instead of sending each packet separately to improve the overall throughput. But it does not meant that the transfer would be postponed forever till accumulating the enough data. It will happen at next earliest possible timing. (Not like caches which will postpone the write till eviction) Instead of I/O device, it will write on write buffer and write buffer will do it soon. It is similar to a server thread passing the requests to a set of worker threads. For example, the CPU or Cache boss needs to post a letter. He puts the request to James, "Hey James! Just post this letter. I need to do a telephone call". James just went out taking the letter. He may be on the way to the post office. But, Boss is not sure when James will complete the post. Just to make sure, he may say "Hey James! Just post this letter and bring me a class of water!". So, the next task can be a dummy read or some valid transaction. But, to make sure that James does all the tasks in orderly fashion, the memory type needs to be set as "Device".

https://www.google.co.jp/#q=Write+buffer+dummy+read

"Strongly ordered" memory type is CPU boss himself is doing all the stuff in orderly fashion.

Store Queues:

Store Queues are considered as one-way (write only) Cache which can do burst write access with memory.

An LCD display system will be used as an example. The CPU draws the picture, the LCD controller displays it.When the underlying content is changed completely, the entire display data must be overwritten. When the cache is being used in the write back mode, previous data is copied to the cache entry because of the cache miss access. The data that was read into the cache is overwritten without being used, so this read operation is wasted. If the store queue is used, there is no read access such as cache fill accesses, only write accesses. 32 bytes size data are written at a time when the data are written back into memory from SQ. For example, with synchronous DRAM, this access becomes a burst access, making a high speed write back access possible. The prefetch (PREF) instruction is used to write back to memory.

Saturday, May 10, 2014

Achieving Fast Boot in Statically built Applications

Strategy:

In domain specific applications such as Automotive where the system start-up needs to be achieved in few hundred millseconds, the application and boot-up sequence needs to be optimized in the following way.

Even though the binary will be one single image, the inner modules can be divided as follows and the corresponding Code, data and BSS sections of each functional module can be scattered and kept with separate sections each with some distinguished start and end symbols.

The boot can be divided into sevaral stages and many modules can be copied into ram and executed on demand, instead of initiating everything at boot-time.

Stage 1: A portion of the executable binary image is loaded and run which is responsible for Reset vector, necessary hardware initialization such as memory map, SDRAM, basic OS initialization and starting up control task

Stage 2: Control task monitors for events and loads and executes the another portion of the binary image which is responsible for a specific functionality.

This is very much similar to making all optional functionalities as Linux modules and loading on-demand. But, this is about how to do in single and static binary image.

Enhancement: Inside each functional module, the initialization functions and termination functions can be defined separately and moved into boot-time initialization module. How to do is described below. This is too similar to module_init() and module_ext() calls.

(Be foolish when asked about what to do. Be wise when asked about how to do.
Products mady by wise people, but made for fools will get great success.)



Monday, May 05, 2014

How modern hardware designs excel software needs?

Initially Intel hardware supported only 32 bit bus which supported only up to 4 GB RAM. Later 4 GB RAM was not enough for servers. So, 4 more bits were added in the hardware bus. Since then, RAM can be extended till 64 GB. In Linux, the Page size is 4 KB. So, remaining 20 bits will be divided into 10-10 bits. Each entry is 2 words (20 bit RPN - 20 bit VPN). Each page table is 8 KB? For Intel, Linux used only 2 level and one dummy level. To support extended bits, 4-10-10 table structure is used. But, still logical address is 32 bits. But, the physical address is 36 bits address. How this is managed? In Linux page table entry, the logical address field remains same as 32 bits. But, the physical address is extended by 4 bits. So, though the physical RAM is 64 GB available, no single process can utilize the whole RAM because its (logical) address space is limited to 32 GB. But, different processes can map different parts of 64 GB RAM into its logical address space and can co-exist in the RAM without any additional overhead of swapping.

Saturday, April 19, 2014

uITRON: ext_tsk vs ter_tsk

① Difference between Task exit and termination

Terminate is same as ext_tsk, but ext_tsk is suicide and ter_tsk is murder. Both will be reactivated in case there are pending requests for that particular task.

② uITRON implemenation of ter_tsk

ER ter_tsk(ID tskid)
{
        If the task itself is calling this function,
                return E_ILUSE;
        Sanity check on arguments
        Enter critical section
        Take the TCB
        If (the task is already in Dormant state) {
                Exit critical section
                return E_OBJ;
        }
        /* A lot of things need to be done */
        /* ter_tsk must be called from other tasks. So, the terminated task
            must be at lower priority. So, it must be ended by just releasing
            resources corresponding to the task and removing from the ready
            queue and making it dormant. And, just continue the execution of
            calling function. No scheduling is required unless otherwise there
            are some pending activation requests (again added in the ready queue)
            and the initial priority is higher than the calling one */
        /* But, think that there are some other special cases where this
           function is called from ISR, but the task is in Running state. This
           means the highest priority running task is getting removed from
           ready queue.
           So, rescheduling needs to be done. When called from Timer event
           handler, scheduling will be done after the handler. So, no issues.
           When this system call is called from interrupt context, just enable
           the flag that the dispatch is delayed before returning the call. */
        if (this function is called from ISR and ) {
                Enable the flag that there is pending dispatch
                /* guess here too the dispatch disable needs to be released. */
                /* Yes! this processing has some inconsistency, that the task is
                   allowed to run after removed from Ready queue and made the
                   status as Dormant. Also, the Dispatch is kept disabled. So,
                   other tasks cannot run. The use case will be when the task
                   disablesdispatch and processing something, interrupt occurs
                   and thetask is terminated from the interrupt handler. */
        }
        /* Normal processing starts here... Release all hold by the task */
        if (the terminating task has disabled the dispatch..
                /* then, ofcourse this should have been called from ISR or
                   timer handlers. (If ISR, then since dispatch is delayed,
                   this task is given time to return its execution and enable
                   the dispatch by itself, then the scheduling will be done
                   from ena_dsp.. when dispatch is disabled even ISR will not
                   reschedule) */
                ..and this system call is called from the timer handler) {
                        and the task that disabled dispatch is the terming one) {
                        Release the dispatch disable (enable).
                        /* As the timer handler is going to reschedule, all
                           system state changed by terming task needs to be
                           brought back, since the terminating one will not
                           execute again. */
                }
        }
        /* In contrary to the exit task, the terminating task may be in the
           mid of processing of kernel objects. So, every possibility of each
           kernel objects being processed in the waiting state needs to be
           considered and released properly */
        /* And also, the TCB needs to be initialized to be in the Dormant state */
        base priority of TCB = current priority = Priority assigned by user
        if (task is waiting in Timeout)
                remove from timer queue
        if ((task is in Ready state and not in suspended)
        /* Suspended task is isolated which will unlinked from all queues */
         or (queued/linked in any other object's wait queue))  {
                Just remove/unlink from the queue;
                if (the task was waiting in the Mutex queue) {
                        /* equillibrium affected */
                        balance_mtx_equillibrium();
                }
                else if (the task is waiting in the message buffer queue) {
                        check the next task in queue can send the message();
                        /* If some task advanced to the head of queue because
                           of deletion of the terming task, then there is
                           chance */
                }
                else if (the task is waiting in the variable mpool queue) {
                        check the next task in the queue can get the memory
                        /* If some task advanced to the head of queue because
                           of deletion of the terming task, then there is
                           chance */
                }
        }
        if (the task has locked mutexes) {
                unlock all mutexes; /* processes the equillibrium */
                /* but, it does not cause any task to change priority */
                set the head pointer to the list of mutexes as zero
        }
        if (task exception handler is defined) {
                /* Regardless of whether the task is in exception handler, just
                   reset the exception handler block. Note that the handler
                   block is not released. So, the pointers will be still valid
                   when the implementation refers when returning from the
                   handler. The release of task exception block needs to be done
                   by def_tex(). Whats done here is that the task's context
                   which is backed up by the tex block is nullified. This is
                   fine as the execution is never going to execute the task.
                   It is justified as follows:
                   1) If the task itself has raised the exception, then this
                      cannot be called from the task itself. If this call has
                      been called from ISR or timer handler, then rescheduling
                      will happen inside/just out of ISR/timer handler. And,
                      since the task is deleted from Ready Queue, the execution
                      will never return to the task or Exception handler.
                      Exception handler itself disappears in halfway. So, the
                      context is no more needed.
                   2) Same as above, even if the task exception is raised from
                      other task. Because, the exception is considered same as
                      the task except that the execution code block is different.
                      So, no matter whether it is task or exception handler, it
                      will be just terminated. The execution will not be back.
                      No meaning for termination otherwise.
                   */
                task exception block's task context backup pointer = NULL;
                task exception block's status = DISABLED;
                task exception block's pending patter = 0;
        }
        if (there are pending activations) {
                /* Activate the task again. Same as activate & start task */
                /* Remember in exit task too. It is activated. But, difference
                   is ext_tsk is killing myself. ter_tsk is killed by others.
                   But, activation on both cases happens there are pending
                   activation requests */
                Move to the high address of stack space (bottom);
                Assume that the context is saved in the stack, so move up one
                context size from the bottom and assign it as current stack
                pointer of the context;
                /* The contents of registers when the task begins executing are
                   not guaranteed. So, not all of the registers but few
                  important registers of the context needs to be initialized */
                /* This will be hardware dependent portion */
                /* Especially, all special purpose register value needs to be initialized */
                /* As if ext_tsk is called by default when exiting the task function, */
                Initialize context's Link register (return address) = ext_tsk function
                According to task attributes such as enabled FPU,
                        Initialize/Enabling of the FPU related registers
                Initialize program status register
                context's program counter = task start address;
                context's argument register = stacd
                Initialize other values and counts of the context;
                status = READY;
                wake-up and suspend count and overrun count = 0;
                Add the task to the Ready Queue of priority
                If (the tw-task priority is higher than the current){
                        Call scheduler
                        Return error code from scheduler
                } else {
                        Exit critical section and return error code from it (E_OK)
                        (return E_OK)
                }
        }
        else {
                set the task status as DORMANT.
        }
        exit critical section and return error code
}


Termination - dealing with a koma patient..

Saturday, March 08, 2014

Caches

1) What are caches?
2) How caches are used in Hardward and Van Neuman architectures to reduce the bottleneck?
3) What are levels of cache?
4) What is fully associative, set associative and not-associative cahces?
5) How is Cache organized and data is stored and retrieved?
6) What is Virtually Indexed and Physically tagged? What is physically indexed and physically tagged?
6) Cache related terms: Cache-hit, Cache-miss, Flush, Invalidate, Cache coherency and Cache snooping, Write-through, Write-back, Dirty bit, Line size, Cache filling, Cache thrashing, Cache Aliasing and Burst transfer.
7) Cache-aware embedded programming: How to tackle with DMA in drivers? Code size and data size within a page to avoid cache thrashing (Linux).
8) What is self-modifying code? What needs to be taken care with self-modifying code?
9) Sample code for Cache Invalidate-all, Cache flush-all and Cache flush or invalidate a particular region.
10) Modern caches, write-buffers and troubleshooting

Friday, March 07, 2014

µITRON Specification 4.0 walkthrough

1) Differentiate on dispatch__: execute and see

Kernel systems calls are atomic.

a) CPU locked -> All interrupts, timer handlers and dispatch NOT necessarily disabled. But, does not occur..(current execution is highest precedence)
b) CPU unlocked
c) Transitional state (neither CPU locked nor CPU unlocked.. In, NORTi Transitional state = CPU locked )

The task suspend system call checks whether the dispatch has been disabled? How it handles the pending dispatch??

Delayed exeuction of service calls - Do system calls execute the dispatch when called from ISR? Or, it has distinction from executing from task contexts?

STM32F4DISCOVERY Speaker interface

Monday, February 24, 2014

Task Management: Just Exit Vs Exit and delete

① Exiting Task

The aeroplane went down for landing. After touched down the runway, it got signal to lift off, and it took off. Exiting task does the same. It resets all the TCB parameters. And, if there is pending activation requests, it starts the task freshly. But, remember that it is removed from Ready queue and added again to maintain the order of activation (precedence) of tasks which are in the same priority. Also remember that the scheduling is done without saving the context of the executing task since it is assumed to exit and no more existing.
Remember one more important thing. The task is not deleted. It should be able to be activated again. So, the TCB is needed to be brought back to the state of after task creation. Especially, the parameters passed by the user in cre_tsk() need to be restored. All allocated items are kept as it is.

② Exiting and Deleting task

Just releasing the resources and calling scheduler not to save current context, but only schedule others. Remember the scheduler (dispatcher) itself acts as unlocking of critical section. It unlocks the critical section before getting scheduled to any other execution point. Whether all calls to the dispatcher has the critical section locked needs to be checked. Otherwise, the masking of interrupt level itself is considered as masking of execution of dispatcher. Masking of any interrupt level just above the task level will cause the dispatcher not to be scheduled and always return to the same task.

The precedence is as follows as per specification.
Precedence:
1) Interrupt Handlers, time event handlers, CPU exception handlers
2) Dispatcher (one of the kernel processes) (Assume this Highest priority task) - Interrupt Level 16
3) Tasks - Interrupt Level 16
③ uITRON implementation of ext_tsk

void ext_tsk(void)
{
        If the called from ISR or Dispatch disabled state or from dispatcher
                return E_CTX;
        Enter critical section
        Take the TCB
        Reset the task priority and base priority to what user had set initially
        if there is taks exception handler defined {
                clear the pending exception pattern
                Disable the exception handling
                Reset backup of task context to NULL, since it is no more going to be used
                /* Hopefully the backup context is not referred, if this is called from
                   inside exception handler */
        }
        Remove the tcb from the Ready queue (it should be in ready queue)
        If (it is holding any mutex) {
                unlock all mutexes as specified below
                set the head pointer to the locked mutex as NULL
        }
        if (there are pending activation requests) {
                Reduce the count by one
                /* Same as sta_tsk and act_tsk. But, one difference is here, you
                   cut the tree on which you are sitting on. You are going to edit the
                   context of yours which exists on the same stack space where the
                   program itself is running. So, atleast you have to make sure that
                   the stack pointer is apart from the context area */
                Set the initial context just above the bottom of the stack
                call assembly routine to reset the stack pointer to just above the context
                /* context initialization same as of sta_tsk, act_tsk */
                context's argument register = stacd
                Initialize context's Link register (return address) = ext_tsk function
                According to task attributes such as enabled FPU,
                        Initialize/Enabling of the FPU related registers
                Initialize program status register
                context's program counter = task start address;
                Initialize other values and counts of the context;
                status = READY;
                wake-up and suspend count and overrun count = 0;
                Add the task to the Ready Queue of priority
                /* Anyway, the scheduler will be called */
                call scheduler not to save current context, but only schedule others
                /* It No more returns here */
        }
        status = DORMANT;
        call scheduler not to save current context, but only schedule others
        /* It No more returns here */
}

void unlock_all_mutexes()
{
        /* Parse through all mutexes locked by the task */
        Take the first mutex locked by the Task
        while (there is mutex locked by the task) {
                Keep the next mutex linked to this mutex (belongs to the same task)
                Isolate(unlink) this mutex by setting the next field to zero
                /* Grant this mutex to one waiting task and wake it up */
                For all tasks waiting in this mutex's queue (from head having highest priority tasks) {
                        Take a task.
                        If it is waiting as Timeout, remove it from timer queue
                        Remove the task from the mutex's queue
                        Set tcb status as Ready
                        /* Sanity check and lock assignment as if it called loc_mtx */
                        If the mutex attribute is Ceiling and the task has higher base priority {
                        /* When ths task is waiting, base priority is changed by chg_pri() */
                                Error code parameter of tcb = E_ILUSE
                                Add the task to the Ready queue
                                If the task's priority is higher than the current task's priority
                                        Set to call scheduler when quitting this function
                                Take next task and continue checking from first
                        } else {
                                If the mutex has CEILING attribute and
                                the ceiling priority is higher than the task priority{
                                        the task (tcb) priority is set to the ceiling priority
                                } else {
                                        the task's priority is set as current highest
                                            priority locking the mutex
                                }
                                Set the task as locking task
                                Add the mutex in the task's queue of mutexes
                                If the task's priority is higher than the current task's priority
                                        Set to call scheduler when quitting this function
                        }
                }
                Assign the next mutex as this mutex
        }
}

④ uITRON implementation of exd_tsk()

void exd_tsk(void)
{
        Enter critical section
        Take the TCB
        Remove the tcb from the Ready queue (it should be in ready queue)
        If (it is holding any mutex) {
                unlock all mutexes as specified in ext_tsk()
        }
        Release the memory allocated for any element in TCB
        /* Bring back the task to non-existent state so that the task entry can be allocated to any other task */
        Assigning NULL to the task entry etc.
        call scheduler not to save current context, but only schedule others
        /* It No more returns here */
}

Unexpectedly Exiting and Deleting is easier than just exiting..

Task Management: Cancel activation

① Cancellation of activations

It is just simple that it makes the pending number of activations to zero in the task control block and returns the (cancelled) pending number of activations.

And, to note that the pending count is count of activations raised when the task is not in Dormant state. When the task exists, it is re-used to activate the task again. But, when the task is deleted, all counts just vanish.

② uITRON Implementation of can_act()

ER can_act(ID tskid)
{
        Sanity check on arguments
        Enter critical section
        Get the count of number of pending activations from the task control block
        Make the number of pending activations for the task to zero
        Exit critical section
        return the count
}

 

Task Management: Start Task Vs Activate Task

 ① About act_tsk()

The fair part of making a simple function into a task is done by act_tsk(). It does the job of setting up the stack memory, setting up the initial register values of the context as if the task now sleeping just before the task's start function. And, it has been called from task exit processing function. The argument will be the value set in the extended information. So, it needs to initialize particular registers to simulate the scenario which is depend on the ABI (Application Binary Interface) specification of the exeuction environment( CPU, compiler, etc). Other registers can be arbitrary values.

② Difference between the act_tsk and sta_tsk

Both are almost same except two things.
1) In sta_tsk(), the argument of the task function is passed from user. But, in act_tsk(), the extended information pointer is passed to the task start function.
2) In act_tsk(), the activation count is accumulated. But, sta_tsk() is not like that. It just starts the task.

③ uITRON implementation of sta_tsk()

ER sta_tsk(ID tskid, VP_INT stacd)
{
        Sanity check on arguments;
        Enter critical section;
        if (task is in the dormant state) {
                Move to the high address of stack space (bottom);
                Assume that the context is saved in the stack, so move up one
                context size from the bottom and assign it as current stack
                pointer of the context;
                /* The contents of registers when the task begins executing are
                   not guaranteed. So, not all of the registers but few
                  important registers of the context needs to be initialized */
                /* This will be hardware dependent portion */
                /* Especially, all special purpose register value needs to be initialized */
                /* As if ext_tsk is called by default when exiting the task function, */
                Initialize context's Link register (return address) = ext_tsk function
                According to task attributes such as enabled FPU,
                        Initialize/Enabling of the FPU related registers
                Initialize program status register
                context's program counter = task start address;
                context's argument register = stacd
                Initialize other values and counts of the context;
                status = READY;
                wake-up and suspend count and overrun count = 0;
                Add the task to the Ready Queue of priority
                If (the tw-task priority is higher than the current){
                        Call scheduler
                        Return error code from scheduler
                } else {
                        Exit critical section and return error code from it (E_OK)
                        (return E_OK)
                }
                exit critical section and return
        }
        exit critical section and return error code
}

④ uITRON Implementation of act_tsk()

ER act_tsk(ID tskid)
{
        Sanity check on arguments;
        Enter critical section;
        if (task is in the dormant state) {
                Move to the high address of stack space (bottom);
                Assume that the context is saved in the stack, so move up one
                context size from the bottom and assign it as current stack
                pointer of the context;
                /* The contents of registers when the task begins executing are
                   not guaranteed. So, not all of the registers but few
                  important registers of the context needs to be initialized */
                /* This will be hardware dependent portion */
                /* Especially, all special purpose register value needs to be initialized */
                /* As if ext_tsk is called by default when exiting the task function, */
                Initialize context's Link register (return address) = ext_tsk function
                According to task attributes such as enabled FPU,
                        Initialize/Enabling of the FPU related registers
                Initialize program status register
                context's program counter = task start address;
                context's argument register = argument passed using extended information
                Initialize other values and counts of the context;
                status = READY;
                wake-up and suspend count and overrun count = 0;
                Add the task in the ready queue
                Add the task to the Ready Queue of priority
                If (the tw-task priority is higher than the current){
                        Call scheduler
                        Return error code from scheduler
                } else {
                        Exit critical section and return error code from it (E_OK)
                        (return E_OK)
                }
                exit critical section and return
        }
        Otherwise, add the call into the activation count;
        If the activation count is more than the maximum,
                set it to the maximum and set error code to E_QOVR;
        exit critical section and return error code
}

If you want your task to run as many times as you revive it, then use act_tsk..

Task Management: Create Task

① Creating Task

All the parameters from user side are passed. They are Task Start address, Stack size, Priority, stack space address if have preferred address space, as only allocation and initialization to default are performed here. Some more attributes such as Task has to be activated just with this call also passed here. Task moves from Non-existent state to Dormant state. If the task is activated inside, taks enters to Ready queue for the first time.

② ITRON implementation of cre_tsk()

ER cre_tsk(ID tskid, T_CTSK *pk_ctsk)
{
        /* Clear distinction between the system calls that can be called from non-task contexts */
        If (called from ISR)
                return E_CTX;
        Sanity check on arguments;
        Enter Critical section;
        Allocate memory for TCB and stack;
        Initialize TCB as follows;
        state = DORMANT, activated=0, lock acquired=0
        base priority=current priority=assigned by user
        stack pointer=Address of the stack space
        exception handler=NULL;
        Initialize the stack space excluding the space for context as
         in sta_tsk the initial context will be formed inside the stack space
        Exit critical section
        if the activate flag is set
                activate the task;
        return E_OK;
}

Create just takes backup of arguments and allocates resources..

Bluetooth Related

1) What is Bluetooth and WLAN frequency range?

Bluetooth - ISM (Industrial, Scientific, Medical) band 2.4 MHz + 83 MHz wide
WiFi too same 2.4 MHz + 83 MHz wide

2) Do not they corrupt each other as both working on the same frequency?

Ofcourse. But, each follow different protocols that facilitates to overcome the loss of data due to inteference.

"Bluetooh Hops Away and Tries Again"
 
Bluetooth divides the band into 79 different 1 MHz channels. And, it uses FHSS (Frequency Hop Spread Spectrum) which means Bluetooth hops into these different channels in predefined manner in sync with peer to transmit the data. For example, one bit on 8th channel, next bit on 29th, next bit on 21th, like that. So, if the WiFi channel (explained next) interference causes a loss of data in Bluetooth, as it hops to the next frequency channel, there is chance to get the data.
 
"WiFi slows down and Tries Again"

WiFi on the other hand, divides the band into 22 MHz channels with fixed frequency range (DSSS - Direct Sequence Spread Spectrum) which is fixed for data transmission of one node. There could be maximum of 11 overlapping channels or 3 non-overlapping channels. (So, there can be no more than three different WiFi networks operating in close proximity to one another.) When Bluetooth interferes WLAN channel, WLAN assumes that collision occured due to stations trying to transmit simultaneously and does retransmission of data similar to Ethernet.
 
There are few methods for co-existence. Recently, WLAN is getting moved to 5.2 GHz frequency band.

3) Difference between different Ethernet protocols?

WLAN - CSMA/CA Carrier Sense Multiple Access/Collision Avoidance - Make sure the medium is idle before Transmission. Cannot listen the medium when transmitting, so cannot detect collision. Transmit full frame. If not acknowledged, retransmit.
 
10BASE Ethernet - Half duplex - CSMA/CD Collision Detection - Wait for the medium to be free, transmit single bit and listen the medium if any collision occured. If so, retry after random period. If no, transmit next bit.
 
100Mbps/Full duplex - Separate wires for transmit and reception and direct connection with peer. So, medium itself made collision free.

4) Does low power Bluetooth use the same band?

Yes. Uses same frequency spectrum range 2.4 GHz ~ 2.4835 GHz ISM Band as of classic Bluetooth. But, uses different set of channels, instead of 79 1MHz channels, uses 40 2MHz channels.

Range is 50m (Classic is 100m)
DataRate 1Mbps (Classic is 1~3Mbps)
Peak current consumption <15ms (Classic is < 30ms)

Bluetooth smart - 極低電力で動作する無線通信規格Bluetooth Low Energy (BLE)に対応を提示するブランド名
                           きょくていでんりょくでどうさするむせんつうしんきかく Bluetooth Low Engegyにたいおうをていじするブランドな

                        BLEはBluetooth 4.0で採用されている、通信可能距離が短く(50m)、通信速度は低速(1Mbps)、ボタン電池で数年稼動する(アイドルの時数uA、動作する時に<15mA)
                        BLEはBluetooth 4.0でさいようされている、つうしんかのうきょりはみじかく、つうしんそくどはていそく、ボタンでんちですうねんかどうさせる

                        小型の機器で使われる(時計、リモコン、。。。。)
                        こがたのききでつかわれる

Bluetooth smart ready - is brand name for computers which support BLE as well as Bluetooth classic

(http://e-words.jp/w/Bluetooth20Smart.html)
(http://en.wikipedia.org/wiki/Bluetooth_low_energy)

5) What is the specification for ANT?

ANT - proprietary open access multicast wireless sensor network
Communicates over the same RF spectrum of 2.4GHz (ISM Band)
When working, consumes around 60uA current.

Bluetooth was not designed for large wireless sensor networks. Still, it can form star network of maximum 8 devices (one master and 7 slaves). But, ANT is for large wireless sensor network. ANT supports file transfer of upto 60 kbps.
 
ANT uses adaptive isochronous networking topology. This scheme is very flexible and within a fixed frequency band, data is transmitted in different time slots. Transmission occurs when there is no interference in the frequency band. The radio transmits for less than 150us  per message. The available number of time slots also determined by the messaging period (time interval between data transfer of each node). If the radio band is crowded, ANT allows application to hop to alternative 1MHz channel in the 2.4 GHz band.

6) What are the products supported?

・ARM based System-On-Chip (ARMベースのシステムオンチップ)
・(Single Chip) IC (シングルチップIC)
・Development Kits (開発キット)
・プロトコルスタック

into four different categories:
1) Bluetooth Low Energy
2) ANT
3) 2.4 GHz RF
4) 1GHz RF

7) Bluetooth support over Linux

BlueZ Linux Bluetooth protocol stack is official Bluetooth stack for Linux.

Directory: linux/net/bluetooth
Configuration option:
Networking support -> Bluetooth subsystem support
 
8) WLAN support over Linux

WLAN has built in support in Linux. Do you remember, WLAN does not have any separate stack as it just uses the same protocol stack with just at hardware level few WLAN drivers and some thin layer to manage the connections comes.

9) PAN setup over Linux

 

 it never ends...

Thursday, February 13, 2014

Task exception: Refer status

① Difference between sns_tex and ref_tex

sns_tex() returns only the disable state of task exception handler. But, ref_tex() returns the enable/status of task exception and pending exception pattern.

② uITRON implementation of sns_tex

BOOL sns_tex()
{
        /* if there is not running task, return TRUE */
        if (task running is just idle task)
                return TRUE;
        Otherwise, take the TCB of whoever executing this task
        Enter critical section
        If exception handler is not defined at all
                Exit critical section and return TRUE;
        If exception is disabled
                Exit critical section and return TRUE;
        otherwise
                Exit critical section and return FALSE;
}
③ uITRON implementation of ref_tex

ER ref_tex(ID tskid, T_RTEX *pk_rtex)
{
        Sanity check on arguments
        Enter critical section
        If the task is in the dormant state or task exception handling
        routine is not defined
                Exit critical section and return E_OBJ
        Assign the texstat field with the exception enable/disable status
        Assign the pndptn field with exception pending pattern
        Exit critical section and return E_OK
}
Exception handler a dog in my house..

Task exception: Enable and Disable of exception

① Enable and Disable of Task Exception

Disabling is just disabling the task exception flag. But, enabling of task exception is not only the enabling of the task exception, but immediately executing the exception handler if there are pending exceptions. Remember in RTOS at each point of instruction execution, the prioritized execution should be secured.

② uITRON implementation of ena_tex

ER ena_tex()
{
        Sanity check on arguments
        Enter critical section
        Get the TCB of the calling task
        Set the flag Exception enabled on the TCB
        if (there is pending exception and Task execution is not inside exception handler)
                raise the exception
        Exit critical section
        return E_OK;
}
③ uITRON implementation of dis_tex

ER dis_tex()
{
        Sanity check on arguments
        Enter critical section
        Get the TCB of the calling task
        Set the flag Exception disabled on the TCB
        Exit critical section
        return E_OK;
}
RTOS is an box of springs each with own compression...

Thursday, February 06, 2014

uITRON: Task Exception Handler - Define and Raise

① Task exception handling routine

Task exception handling routine will run in the same task's context that means in the same priority, stack and with the same context variables which are shared between other tasks such as error code. But, in the view point of the task itself, it is a out-of-myway execution which means the execution path of exception handler is completely independent and asynchronous similar to interrupt handler. So, from the view point of task itself, a separate context which is independent of the task's context is reserved for the exception handler except when the task itself raises the exception handling. When the task itself raises the exception handling the system call executes the exception handler before returning to the task. So, it is more like function call which synchronous to the task execution. So, separate context is not reserved in this case.

② uITRON implementation of  def_tex()

ER def_tex(ID tskid, T_DTEX *pk_dtex)
{
        Sanity check on arguments
        Enter critical section (Interrupt Disable)
        Take task ID if the the task is self
        if (the task does not have exception handler already defined) {
                Assume pending pattern = 0;
                Assume status is Disabled.
                Assume stack pointer is NULL;
                Set the pending pattern = 0;
                Set the status Disabled;
                Set the stack pointer as NULL;
                Assign the exception handler given in parameter;
        } else {
                Just overwrite the exception handler given in parameter;
        }
        /* If both are null, then nothing to do. */
        Exit critical section and return E_OK;
}
③ uITRON implementation of ras_tex()

ER ras_tex(ID tskid, TEXPTN rasptn)
{
        Sanity check on arguments
        Enter critical section (Interrupt Disable)
        Take task ID if the the task is self
        Get the Task Control Block from the Task ID
        Logical OR the pattern given in the parameter with TCB's exception pattern
        If task exception status is not disabled and not inside task exception handler
        {
                /* Execute the exception handler or do preparation to execute in future */
                Preserve the task's context pointer in the exception block
                /* Mainly the exception handler needs to be executed in task's context */
                If (the task itself raising task exception) {
                        /* Task status is ready and */
                        /* Task ID is at the head of ready queue and */
                        /* But, Not in interrupt context. */
                        /* This is the context to run exception handler. */
                        /* So, Just call as a function call before returning to task */
                        /* till all pending patterns are cleared */
                        Take the extended information pointer from the TCB
                        while (there are pending exceptions) {
                                Take the pending pattern from TCB;
                                Make the pending pattern to zero in the TCB
                                Take the exception handler pointer
                                exit from critical section
                                Call the exception handler with pending pattern and extended information
                                enter critical section
                        }
                        /* its over */
                        Assign the exception block's context to NULL;
                        /* I'm out of exception handler */
                } else {
                        /* In the following two contexts, it enters here */
                        /* 1) This task is Ready. But, now inside interrupt handler. */
                        /* Just volatile registers are inside the context. Anyhow, the */
                        /* exception handler needs to be executed in the task's context */
                        /* just after coming out of interrupt handler */
                        /* 2) The task is preempted. The task has all registers and */
                        /* shared context variables inside the context. The handler */
                        /* needs to be executed when the task is yielded to run */
                        /* For the exception handler, the register set is not needed. */
                        /* But, all other context is required. There are some processing of */
                        /* creating new context for exception handler and switching of context */
                        /* is required. So, internal wrapper function is assigned to execute when */
                        /* the task become ready to run. */
                        Assign internal wrapper function
                        Calculate the pointer one context unit down to currently saved
                        Initialize the new context for exception handler.
                        if (task is preempted) {
                        /* task is not ready */
                                Take copy of the shared context variables into exception handler's
                        }
                        Set the internal handler function as execution function
                        Set the new context pointer as task's context
                }
        }
        /* otherwise nothing to do now */
        Exit critical section and return E_OK;
}
void wrapper_internal(ER ercd)
{
        /* Remember that you should not forget take in the error code updated */
        /* in other contexts. It is the only shared context variable to updated. */
        /* All others are read-only */
        Take tcb of the task executing
        Take the exception block
        Enter critical section
        Take the pending pattern from TCB;
        Take the extended information
        If (task was preempted one)
                /* shared context variables are saved by this exception module */
                Update the error code in the task's context
        Make the pending pattern to zero in the TCB
        for each valid bit in the pending pattern {
        till (there are pending exceptions) {
                /* Till all pending pattern is cleared */
                Take the exception handler
                exit critical section
                execute the exception handler
                enter critical section
                Take the pending pattern from TCB;
                Make the pending pattern to zero in the TCB
        }
        Restore back the task's context pointer from the exception block
        Reschedule the tasks;
}

A soft interrupt...