Wednesday, December 19, 2018

USB 3.0 - Arch Overview

USB 3.0 - Arch & Impl - Overview

Download this and run in presentation mode. Some of the slides are meant for being run in PPT mode which otherwise would NOT be readable

Monday, October 8, 2012

Difference between RAMfs and TMPfs


Ramfs vs Tmpfs

Primarily both ramfs and tmpfs does the same thing with few minor differences.
  • Ramfs will grow dynamically.  So, you need control the process that writes the data to make sure ramfs doesn’t go above the available RAM size in the system. Let us say you have 2GB of RAM on your system and created a 1 GB ramfs and mounted as /tmp/ram. When the total size of the /tmp/ram crosses 1GB, you can still write data to it.  System will not stop you from writing data more than 1GB. However, when it goes above total RAM size of 2GB, the system may hang, as there is no place in the RAM to keep the data.
  • Tmpfs will not grow dynamically. It would not allow you to write more than the size you’ve specified while mounting the tmpfs. So, you don’t need to worry about controlling the process that writes the data to make sure tmpfs doesn’t go above the specified limit. It may give errors similar to “No space left on device”.
  • Tmpfs uses swap.
  • Ramfs does not use swap.

4. Disadvantages of Ramfs and Tmpfs

Since both ramfs and tmpfs is writing to the system RAM, it would get deleted once the system gets rebooted, or crashed. So, you should write a process to pick up the data from ramfs/tmpfs to disk in periodic intervals. You can also write a process to write down the data from ramfs/tmpfs to disk while the system is shutting down. But, this will not help you in the time of system crash.
Table: Comparison of ramfs and tmpfs
ExperimentationTmpfsRamfs
Fill maximum space and continue writingWill display errorWill continue writing
Fixed SizeYesNo
Uses SwapYesNo
Volatile StorageYesYes

If you want your process to write faster, opting for tmpfs is a better choice with precautions about the system crash.

NFR tips


1) Memory Hogging Tip
      a) Create a tmpfs
      b) Write data to it This will consume RAM

       mount -t tmpfs tmpfs -o size=512m dd if=/dev/zero of=/test bs=1024 count=524288 

2) CPU hogging
    #!/bin/bash 
    # This script will fill 1GB zeros to log.txt, 1KB at a time. 
    # This is done to create a load on the CPU 
     while true
     do 
     dd if=/dev/zero of=log.txt bs=1024 count=10485700 
     done

Getting the top comand output to a file


top -n 1 -b > file

Wednesday, December 7, 2011

Booting Linux on core 1 while uboot on core 0

In uboot --

Change the existing line

123 theKernel (0, machid, bd->bi_boot_params);

To the below

122 #if 0
123 theKernel (0, machid, bd->bi_boot_params);
124 /* does not return */
125 #else
126 // addr = CORE1_DEST_DOWN_ADDR;
127 #define SPRMC_CPU_ID 1
128 #define IRQ_AP_START 3
129 addr = 0x8000;
130 *(volatile unsigned long *)(SCRATCH_REG_BASE) = (unsigned long)addr;
131 printf ("## machid: %x, Starting yw at 0x%8x ...\n",machid, addr);
132 REG_WRITE(MPCORE_GIC_IntEnable(IRQ_AP_START), BIT(IRQ_AP_START));
133 REG_WRITE(MPCORE_GIC_Control, INT_CONTROL_ENABLE);
134 do_send_ipi_linux(IRQ_AP_START, 1< 135 #endif


In kernel ---
arch/arm/kernel/head.S
in kernel startup entry point.
add machid to r1

Disclaimer:
I need to confirm this. have taken from somebody

Thursday, March 24, 2011

Boot up Sequence and Interrupts in the kernel(ARM)

skip to main | skip to sidebar
Tech stuff.

Tech stuff contains posts related to systems programming, linux, and processor architectures.
Friday, December 14, 2007
Arm MMU in linux: page table Initialization and tweaks for integeration with Memory management code.
This post covers details of MMU initialization code of linux 2.6.11 kernel for ARM and few internal tweaks used for mapping arm page tables to x86 style page tables which linux memory management code expects. We'll cover only architecutre specific details, generic MM code of kernel will not be covered here. For all the architecutre specific details we take ARM 11 (Architecture V6) as our reference.

Following conventions are used in this writeup:

* All 'C' function names are in italics.
* All 'Assembly' function names and lables are metioned in bold italics.
* No file names will be mentioned here (with exception of assembly files), use ctags.
* All details are for uniprocessor system, nothing related to SMP is covered here.

Kernel's execution starts at stext in (arch/arm/kernel/head.S) , at this point kernel expects that MMU is off, I-cache is off, D-cache is off. After looking up of processor type and machine number, we call __create_page_tables which sets up the initial MMU tables for which are used only during initialization of MMU. Here we create MMU mapping tables for 4MB of memory starting from kernel's text (More preciesly it starts at a 1MB section in which kernel's text starts). Following is the code snippet which creates these mappings:

-----------------------------

_create_page_tables:


1. ldr r5, [r8, #MACHINFO_PHYSRAM] @ physram
2. pgtbl r4, r5 @ page table address
3. mov r0, r4
4. mov r3, #0
5. add r6, r0, #0x4000
6. 1: str r3, [r0], #4
7. str r3, [r0], #4
8. str r3, [r0], #4
9. str r3, [r0], #4
10. teq r0, r6
11. bne 1b
12. ldr r7, [r10, #PROCINFO_MMUFLAGS] @ mmuflags
13. mov r6, pc, lsr #20 @ start of kernel section
14. orr r3, r7, r6, lsl #20 @ flags + kernel base
15. str r3, [r4, r6, lsl #2] @ identity mapping
16. add r0, r4, #(TEXTADDR & 0xff000000) >> 18 @ start of kernel
17. str r3, [r0, #(TEXTADDR & 0x00f00000) >> 18]!
18. add r3, r3, #1 <<>
19. str r3, [r0, #4]! @ KERNEL + 1MB
20. add r3, r3, #1 <<>
21. str r3, [r0, #4]! @ KERNEL + 2MB
22. add r3, r3, #1 <<>
23. str r3, [r0, #4] @ KERNEL + 3MB


-----------------------------
In this function we first of all find out the physical address where our RAM starts, and locate the address where we'll store our inital MMU tables (line #1 and #2). We create these inital MMU tables 16kb below kernel entry point. Line #12- #15 create an identity mapping of 1MB starting from kernel entry point (physical address of kernel entry, i.e stext). Here we do'nt create a second level page table for these mapping, instead of that we specify in first level descriptor that these mappings are for section (each section mapping is of size 1MB). Simiarly we create mapping for 4 more sections (these 4 are non identity mappings, size of each section is 1MB here also) starting at TEXTADDR (virtual address of kernel entry point)


so the initial memory map looks something line this:



After the initial page tables are setup, next step is to enable MMU. This code is tricky, does lot of deep magic.

----------------------------

1. ldr r13, __switch_data @ address to jump to after mmu has been enabled
2. adr lr, __enable_mmu @ return (PIC) address
3. add pc, r10, #PROCINFO_INITFUNC
4.

.type __switch_data, %object

5. __switch_data: .long __mmap_switched
6. .long __data_loc @ r4
7. .long __data_start @ r5
8. .long __bss_start @ r6
9. .long _end @ r7
10. .long processor_id @ r4
11. .long __machine_arch_type @ r5
12. .long cr_alignment @ r6
13. .long init_thread_union+8192 @ sp

-----------------------------


line #1 puts virtual address of __mmap_switched in r13, after enabling MMU kernel will jump to address in r13. The virtual address that is used here is not from identity mapping, but it is PAGE_OFFSET + physical address of __mmap_switched. And now since in __mmap_switched we start refering to virtual addresses of variables and functions, so starting from __mmap_switched is no longer position independent.
At line #2-#3, we put position independent address of __enable_mmu ('adr' Psuedo instruction translates to PC relative addressing, that's why it is position independent) and jumps to at a offset of PROCINFO_INITFUNC (12 bytes) in __v6_proc_info structure (arch/arm/mm/proc-v6.S). At PROCINFO_INITFUNC in __v6_proc_info we have a branch to __v6_setup, which does following setup for enabling MMU:


* Clean and Invalidate D-cache and Icache, and invalidate TLB.
* Prepare the control register1 (C1) value that needs to be written when enabling mmu, and return the value which needs to be written in C1.

As __v6_setup returns we enter __enable_mmu, which just sets Cache enable bits, branch-prediction enable bits in 'r' which is the value to be written in C1 (value to be written in C1 was returned in 'r0' by __v6_setup) and then calls __turn_mmu_on.

--------------------------------------

__turn_mmu_on:

1. mov r0, r0
2. mcr p15, 0, r0, c1, c0, 0 @ write control reg
3. mrc p15, 0, r3, c0, c0, 0 @ read id reg
4. mov r3, r3
5. mov r3, r3
6. mov pc, r13

--------------------------------------

__turn_mmu_on just writes 'r0' to C1 to enable MMU. Line #4 and #5 are the nops to make sure that pipeline does not contain and invalid address access when C1 is written. Line #6 'r13' is moved in 'pc' and we enter __mmap_switched. Now MMU is ON, every address is virtual no physical addresses anymore. But the final kernel page tables are still not setup (final page tables will be setup by paging_init and mappings created by __create_page_tables will be discarded), we are still running with 4Mb mapping that __create_page_tables had set it for us. __mmap_switched copies the data segment if required, clears the BSS and calls start_kernel.

The mappings page table mappings that we discussed above makes sure that the position dependent code of kernel startup runs peacefully, and these mappings are overwritten at later stages by a function called paging_init( ) ( start_kernel( ) -> setup_arch( )-> paging_init( )).

paging_init() populates the master L1 page table (init_mm) with linear mappings of complete SDRAM and the SOC specific address space (SOC specific memory mappings are created by mdesc->mapio() function, this function pointer is initialized by SOS specific code, arch/arm/mach-*). So in master L1 page table (init_mm) we have mappings which map virtual addresses in range PAGE_OFFSET - (PAGE_OFFSET + sdram size) to physical address of SDRAM start - (physical address of SDRAM start + sdram size). Also we have SOC specific mappings created by mdesc->mapio() function.

One more point worth noting here is that whenever a new process is created, a new L1 page table is allocated for it, and the kernel mappings (sdram mapping, SOC specific mappings) are copied to it from the master L1 page table (init_mm). Every process has its own user space mappings so no need to copy anything from anywhere.

Handling of mapings for VMALLOC REGION are is bit tricky, because VMALLOC virtual addressed are allocated when a process calls vmalloc( ). So if we have some processes' which were created before the process which called vmalloc then their L1 page tables will have no maping for new vmalloc'ed region. So how this is taken care of is very simple, the mappings for vmalloc'ed region are updated in the master L1 page table (init_mm) and when a process whose page tables do not have newly created mapping accesses the newly vmalloc'ed region, a page fault is generated. And kernel handles page faults in VMALLOC region specially by copying the mappings for newly vmalloc'ed area to page tables of the process which generated the fault.
Tweaks for integerating ARM 2 level page tables with linux implementation of 3 level ix86 style page tables

1. Linux assumes that it is dealing with 3 level page tables and ARM has 2 level page tables. For handling this, for ARM in ARCH include files __pmd is defined as a identity macro in (include/asm-arm/page.h):
-------------------------------------------------

#define __pmd(x) ((pmd_t) { (x) } )
--------------------------------------------------

So effectively for ARM, linux is told that pmd has just one entry, effectively bypassing pmd.

2. Memory management code of in Linux expects ix86 type page table entries, for example it uses 'P' (present ), 'D' (dirty) bits but ARM page table entries (PTEs) don't have these bits. As a workaround to provide ix86 PTE flags, what ARM page table implementation does is that, it tells linux that PGD has 2048 entries of 8 bytes each (whereas ARM hardware level 1 pagetable has 4096 entries of 4 bytes each).

Also it tells Linux that each PTE table has 512 entries (whereas ARM hardware PTE table of 256 entries).This means that the PTE table that is exposed to Linux is actually 2 ARM PTE tables, arranged contigously in memory. NowAfter these 2 ARM PTE tables (lets say h/w PTE table 1 and h/w PTE table 2), 2 more PTE tables (256 entries each, say linux PTE table 1 and 2) are allocated in memory contiguous to Arm hardware page table 2. Linux PTE table 1 and 2 contains PTE flags of ix86 style corresponding to entries in ARM PTE table 1 and 2. So whenever Linux needs ix86 style PTE flags it uses entries in Linux PTE table 1 and 2. ARM never looks into Linux PTE table 1 and 2 during hardware page table walk, it uses only h/w PTE tables as mentioned above. Refer to include/asm-arm/pgtable.h (line: 20-76) for details of how ARM h/w PTE table 1 and 2, and linux PTE table 1 and 2 are organized in memory.

So here we conclude the architecture specific page table related stuff for ARM.

Posted by pankaj at 1:28 AM 2 comments
Friday, November 16, 2007
The story Interrupt handling in linux 2.6.11 on ARM.

This post explains how the interrupts are handled in linux kernel, what homework kernel has to do before first interrupt is recieved. We took 2.6.11 kernel as reference, and for architecture specific details we used a ARM11 based devlopment board.

Following conventions are used in this writeup:

* All 'C' function names are in italics.
* All 'Assembly' function names and lables are metioned in bold italics.
* No file names will be mentioned here (with exception of assembly files), use ctags.
* All details are for uniprocessor system, nothing related to SMP is covered here.
* Any other convention - ???? :) NO.

We'll cover the whole interrupt stuff in two sections:

* Interrupt setup - Explanation of Generic and architecture specific setup that kernel does.

* Interrupt handling - Explanation of what happens after processor recieves an interrupt.

1. Interrupt setup

start_kernel( ) is the first 'C' function that opens its eyes when kernel is booting up. It intializes various subsystems of the kernel, including IRQ system. Intialization of IRQ requires that you have valid vector table in place and you have first level interrupt hadlers in place, both of these things are architecture specifc. Lets setup the vector table first.

start_kernel( ) calls a function called trap_init( ) which does following:

* Call __trap_init() to setup exception vector table at location 0xffff0000.
* Flush the icache in range 0xffff0000 to 0xffff0000 + PAGE_SIZE. This is required because __trap_init( ) moves the vector table and vector stubs to 0xffff0000.

Vector table and vector stub code for ARM resides in arch/arm/kernel/entry-armv.S file. In this file you'll find implementaion of __trap_init( ) funtion. Following is a code snippet from entry-armv.S, we'll go in details of this code:

----------------------------------------------------

1.
.equ __real_stubs_start, .LCvectors + 0x200
2.
.LCvectors:
3.
swi SYS_ERROR0
4.
b __real_stubs_start + (vector_und - __stubs_start)
5.
ldr pc, __real_stubs_start + (.LCvswi - __stubs_start)
6.
b __real_stubs_start + (vector_pabt - __stubs_start)
7.
b __real_stubs_start + (vector_dabt - __stubs_start)
8.
b __real_stubs_start + (vector_addrexcptn - __stubs_start)
9.
b __real_stubs_start + (vector_irq - __stubs_start)
10.
b __real_stubs_start + (vector_fiq - __stubs_start)
11.
ENTRY(__trap_init)
12.
stmfd sp!, {r4 - r6, lr}
13.
mov r0, #0xff000000
14.
orr r0, r0, #0x00ff0000 @ high vectors position
15.
adr r1, .LCvectors @ set up the vectors
16.
ldmia r1, {r1, r2, r3, r4, r5, r6, ip, lr}
17.
stmia r0, {r1, r2, r3, r4, r5, r6, ip, lr}
18.
add r2, r0, #0x200
19.
adr r0, __stubs_start @ copy stubs to 0x200
20.
adr r1, __stubs_end
21.
1: ldr r3, [r0], #4
22.
str r3, [r2], #4
23.
cmp r0, r1
24.
blt 1b

LOADREGS(fd, sp!, {r4 - r6, pc})

-------------------------------------------------------------
In the code snippet given above vector table is between line 4- 10. As we can see this vector contains branch instruction for branching to exception handler code which also resides in same file (arm-entryV.S). Vector table contains the branch instructions for all the exceptions defined in ARM (Undefined instruction, SWI, data abort, prefecth abort, IRQ, and FIQ). The most important thing to note about this vector table is that branch instructions are used for all exceptions except SWI. Using branch instruction instead of loading PC directly with the exceptions handler address makes this code position independent. Since branch instruction take offset (+ive or -ve) from current PC, this code will run fine as long as the offset between vector table instructions and the exception handlers is maintained as desired by this code. And It is assumed here that exception handlers will be at +0x200 offset from starting address of vector table.

__trap_init( ) function copies the vector table at location 0xffff0000 (line 13-17) and copies the exception handlers at 0xffff0200 (line 18-24). Remember that addresses we are talking about here are virtual addresses.

So we are done with setting up vector tables and the exception handlers. If you want then you can hook your exception handler directly to the vector table, so that you bypass all linux interrupt handling code, which is pretty heavy. But if you do so then you'll have to get your hands dirty with all the architecture details which kernel handles beautifully and cleanly.

After setting up vector tables start_kernel ( ) calls init_IRQ() to set up kernel IRQ handling infrastructure, on ARM we have 32 hard interrupts for which kernel kernel sets up the a default desctiptor called bad_irq_desc, which has do_bad_IRQ( ) as IRQ handler. Then init_IRQ( ) calls init_arch_irq( ), here the architecture specfic code has to setup the IRQ handlers for 32 IRQs, if not set then do_bad_IRQ( ) will handle the IRQs. On our reference architecture we setup do_level_IRQ( ) as IRQ handlers of all the IRQs except the system timer IRQ. This is the second place where you can bypass kernel IRQ handlers and hook your IRQ handler directly. If you do'nt have requirement of hooking your IRQ handler here then just let do_level_IRQ( ) handle the IRQs then you can register your IRQ handlers with request_irq() in traditional way, and kernel will call your IRQ handler whenever interrupt occurs hiding all the dirty arch details :)

So now we have our IRQ infrastructure in place, and various modules can register thier IRQ handlers through request_irq(). When you call request_irq( ) kernel appends your IRQ handler to list of IRQ handlers registered for that particular IRQ line, it does not change the exception vector table.

Now lets see what happens after interrupt is recieved.

2. Interrupt Handling

When a IRQ is raised, ARM stops what it is processing ( Asuming it is not processing a FIQ!), disables further IRQs (not FIQs), puts CPSR in SPSR, puts current PC to LR and swithes to IRQ mode, refers to the vector table and jumps to the exception handler. In our case it jumps to the exception handler of IRQ. following is the snippet of code for exception handler code for IRQ (again from entry-armV.S file):

------------------------------------------------------------------------

1. vector_irq:
2. ldr r13, .LCsirq
3. .if \correction
4. sub lr, lr, #\correction
5. .endif
6. str lr, [r13] @ save lr_IRQ
7. mrs lr, spsr
8. str lr, [r13, #4] @ save spsr_IRQ
9. mrs r13, cpsr
10. bic r13, r13, #MODE_MASK
11. orr r13, r13, #MODE_SVC
12. msr spsr_cxsf, r13 @ switch to SVC_32 mode
13. and lr, lr, #15
14. ldr lr, [pc, lr, lsl #2]
15. movs pc, lr @ Changes mode and branches
16. .long __irq_usr @ 0 (USR_26 / USR_32)
17. .long __irq_invalid @ 1 (FIQ_26 / FIQ_32)
18. .long __irq_invalid @ 2 (IRQ_26 / IRQ_32)
19. .long __irq_svc @ 3 (SVC_26 / SVC_32)

--------------------------------------------------------------------------

In the above snipped a macro called vector_stub has been intensionally expanded to improve readability. So when ARM refers to the vector table it follows the branch and lands up at line 2. At this moment ARM is in IRQ mode, IRQs are disabled, LR contains PC of when interrupt occured and SPSR contains CPSR of when interrupt occured. Since we are in IRQ mode so r13 (SP) is banked, so we load SP with address of a small stack frame that we have created at __temp_irq (.LCsirq contains address of __temp_irq). This stack is only used when we are are in IRQ mode.

In lines 6-8 we save LR and SPSR on the temporary IRQ stack (__temp_irq). And we switch to SVC mode (line 10-12). After this basic setup is done depending on the mode in which ARM was there when interrupt occured we switch to specific handler. We'll assume that ARM was executing in SVC mode, so we'll look ino the details of __irq_svc .

__irq_svc saves r0-12 on SVC mode stack (i.e kernel stack of process which was interrupted), reads LR and SPSR from temporary IRQ stack (__temp_irq) and saves them on SVC mode stack, increments the preemt count and then calls get_irqnr_and_base to find out the IRQ line number. Each architecutre has to provide implementation of get_irqnr_and_base, in which it has to query the Interrupt Controller in ARCH specific way to find out which IRQ line raised this interrupt.

After doing all this __irq_svc calls asm_do_IRQ(), Finally we are out of assembly code, now life will be simpler :). And after asm_do_IRQ returns __irq_svc will restore the state of process which was interrupted.

asm_do_IRQ( ) just calls the IRQ handler that was registered by architecure code (refer to section 1), in our case we had set do_level_irq( ) as interrupt handler for all IRQs except timer IRQ. so for all IRQs except timer do_level_irq( ) will handle our interrupts.

do_level_irq() first ACKs the interrupt, by calling architecure specific ACK function. On our reference architecture we just mask this interrupt line, which means that no IRQs of same IRQ line will be allowed until all the IRQ handlers have completed their job. After this do_level_irq( ) checks whether we have any action registered for this IRQ (the interrupt handler that you register through request_irq ( ) are called actions). If there is an action registered then __do_irq( ) is called which in trun enables the interrupts (remember ARM had disabled it) except current IRQ line, and executes the actions.

After all actions have completed excecuting, IRQ line for which interrupt was raised is unmasked and do_level_irq() returns. After this interrupt handling is complete __irq_svc restores the state of interrupted process and that process lives happily until another interrupt bugs it again :)

That was the overview of interrupt handling in linux on ARM, we hope it was useful :)

- Pankaj And Sripurna.
Courtesy: http://pankaj-techstuff.blogspot.com/

Monday, February 21, 2011

Printing out all the strings in the binary

Use the strings command

strings

Mounting Remote machine using ssh

sshfs :/home/zakir/ /mnt

Using netcat for chatting and file transfer

Run

At server
nc -l 1234

At client
nc 1234


Start chatting

For file transfer
nc -vv -l 5678 > dump.mp3

Receive
nc -vv -l 5678 < dump.mp3

Using Zenity to create the dialog boxes

Zenity is a tool that help you to create a common functional GTK+ dialogs. It have various dialogs that each of them have different ways of presenting data and acquire data from user input.

We have introduce how to make use of GUI dialog box in Using GUI dialog box, where we give an example of how zenity create a question dialog box. Besides question dialog box, zenity can create more than that, such as calendar, entry, error, info, file selection, list, notification, progress, warning, scale and text info. In this tutorial, we would like to illustrate how to create every single zenity dialog by examples.

zenity --warning --text "Could you please tell me who you are"

How to create zenity calendar dialog?
You are allow to specify the initial selection of date in calendar dialog, specified with options –day –month –year. The default selection will be today’s date. Zenity will returns the date selected by user.

Squeeze multiple blank lines to one

Documents like RFCs may contain many blank-line blocks.

To save the trees, i always squeeze multiple blank lines down to single blank line, before printing.

Once I did this manually (yes, it’s like hell), but now I use cat -s:

cat -s rfc2324.txt | tr -d '\\f' | lpr

I use tr -d to remove any form feed character, and lpr will submit the document for printing.

Sunday, January 30, 2011

Remote debugging using gdbserver

Remote debugging is rather straightforward:

On the target platform, launch the application with GDBserver, while specifying the host and port for listening to an incoming TCP connection:

gdbserver HOST:PORT PROG [ARGS ...]
gdbserver 10.19.103.55:123 test_rsh_sw.bin r
sh/1bit/

On the development workstation, launch the cross-target GDB:

arm-none-linux-gnueabi-gdb PROG

Be sure to specify the non-stripped executable. At the GDB console, type:

target remote HOST:PORT


break main
continue

These commands will connect GDB to the GDBserver running on the target platform, set a breakpoint at the start of the program, and let it run until it reaches that first breakpoint.

You can also attach GDBserver to a process that's already running:

gdbserver HOST:PORT --attach PID

The process is then stopped, and you can then debug it with a remote GDB.

Wednesday, December 1, 2010

What is an address space

When a program is built(compilation, assembler invocation, and linking)
it is stored in a file with a special format. One such format is
ELF(Executable and Linking Format)in Unix like systems. It has the
necessary information ( in the ELF header and program header) to help
the program loader to load and create the process image in memory at
runtime, and also do run time linking (for shared libraries linked
dynamically).
At the time program is built, storage for all uninitialised data (static or
global) are not allocated, but only the total size is noted in program
header table of the ELF file. Later when program is being loaded, loader
read the metadata from the ELF file and allocate one large chunk (page
aligned) of memory to hose all such variables. This section is called
BSS(Block Static Storage or Block started by symbol).
Data( storage for all initialized static and global variables) and STACK
section should be familiar to you. HEAP is created by dynamic invocation
by memory-alloc routines of your program. In addition to this there will
be shared memory mappings as well. If you process a file using mmap()
system call interface, those regions are also mapped to your program.
Now the sum total of all such memory is called the address space of your
program.

Now what’s an address? Is that a virtual address, physical address
or logical address?
The value you see when you apply an & operator to a C variable
is actually the program-relative logical address. It has to be
processed by segmentation unit(coupled with the value in the CS
register) to create a linear address and then processed by the
paging unit to create the physical address in your RAM. So these
details are not at the control of C, but is at the control of the
memory management subsystems of the operating system.

Tuesday, November 9, 2010

USB Enumeration Process

Typical USB 2.0 Sequence

The steps below are a typical sequence of events that occurs during enumeration of a USB 2.0 device under Windows. Device firmware shouldn’t assume that enumeration requests and events will occur in a particular order. To function successfully, a device must detect and respond to any control request or other bus event at any time.

1. The system has a new device. A user attaches a device to a USB port, or the system powers up with a device attached. The port may be on the root hub at the host or on a hub that connects downstream from the host. The hub provides power to the port, and the device is in the Powered state. The device can draw up to 100 mA from the bus.

2. The hub detects the device. The hub monitors the voltages on the signal lines (D+ and D-) at each of its ports. The hub has a pull-down resistor of 14.25k–24.8kW on each line. A device has a pull-up resistor of 900–1575W on D+ for a full-speed device or D- for a low-speed device. High-speed-capable devices attach at full speed. On attaching to a port, the device’s pull-up brings its line high, enabling the hub to detect that a device is attached. On detecting a device, the hub continues to provide power but doesn’t yet transmit USB traffic to the device. Chapter 15 has more on how hubs detect devices.

3. The host learns of the new device. Each hub uses its interrupt endpoint to report events at the hub. The report indicates only whether the hub or a port (and if so, which port) has experienced an event. On learning of an event, the host sends the hub a Get Port Status request to find out more. Get Port Status and the other hub-class requests described are standard requests that all hubs support. The information returned tells the host when a device is newly attached.

4. The hub detects whether a device is low or full speed. Just before resetting the device, the hub determines whether the device is low or full speed by examining the voltages on the two signal lines. The hub detects the device’s speed by determining which line has a higher voltage when idle. The hub sends the information to the host in response to the next Get Port Status request. A USB 1.x hub may instead detect the device’s speed just after a bus reset. USB 2.0 requires speed detection before the reset so the hub knows whether to check for a high-speed-capable device during reset as described below.

5. The hub resets the device. When a host learns of a new device, the host sends the hub a Set Port Feature request that asks the hub to reset the port. The hub places the device’s USB data lines in the Reset condition for at least 10 ms. Reset is a special condition where both D+ and D- are logic low. (Normally, the lines have opposite logic states.) The hub sends the reset only to the new device. Other hubs and devices on the bus don’t see the reset.

6. The host learns if a full-speed device supports high speed. Detecting whether a device supports high speed uses two special signal states. In the Chirp J state, only the D+ line is driven and in the Chirp K state, only the D- line is driven.

During the reset, a device that supports high speed sends a Chirp K. A high-speed-capable hub detects the Chirp K and responds with a series of alternating Chirp K and Chirp J. On detecting the pattern KJKJKJ, the device removes its full-speed pull-up and performs all further communications at high speed. If the hub doesn’t respond to the device’s Chirp K, the device knows it must continue to communicate at full speed. All high-speed devices must be capable of responding to control requests at full speed.

7. The hub establishes a signal path between the device and the bus. The host verifies that the device has exited the reset state by sending a Get Port Status request. A bit in the returned data indicates whether the device is still in the reset state. If necessary, the host repeats the request until the device has exited the reset state.

When the hub removes the reset, the device is in the Default state. The device’s USB registers are in their reset states, and the device is ready to respond to control transfers at endpoint zero. The device communicates with the host using the default address of 00h.

8. The host sends a Get Descriptor request to learn the maximum packet size of the default pipe. The host sends the request to device address 00h, endpoint zero. Because the host enumerates only one device at a time, only one device will respond to communications addressed to device address 00h even if several devices attach at once.

The eighth byte of the device descriptor contains the maximum packet size supported by endpoint zero. A Windows host requests 64 bytes but after receiving just one packet (whether or not it has 64 bytes), the host begins the Status stage of the transfer. On completing the Status stage, Windows requests the hub to reset the device as in step 5 above. The USB 2.0 specification doesn’t require a reset here. The reset is a precaution that ensures that the device will be in a known state when the reset ends.

9. The host assigns an address. When the reset is complete, the host controller assigns a unique address to the device by sending a Set Address request. The device completes the Status stage of the request using the default address and then implements the new address. The device is now in the Address state. All communications from this point on use the new address. The address is valid until the device is detached, a hub resets the port, or the system reboots. On the next enumeration, the host may assign a different address to the device.

10. The host learns about the device’s abilities. The host sends a Get Descriptor request to the new address to read the device descriptor. This time the host retrieves the entire descriptor. The descriptor contains the maximum packet size for endpoint zero, the number of configurations the device supports, and other basic information about the device.

The host continues to learn about the device by requesting the one or more configuration descriptors specified in the device descriptor. A request for a configuration descriptor is actually a request for the configuration descriptor followed by all of its subordinate descriptors up to the number of bytes requested. A Windows host begins by requesting just the configuration descriptor’s nine bytes. Included in these bytes is the total length of the configuration descriptor and its subordinate descriptors.

Windows then requests the configuration descriptor again, this time requesting the number of bytes in the retrieved total length. The device responds by sending the configuration descriptor followed by all of the configuration’s subordinate descriptors, including interface descriptor(s), with each interface descriptor followed by any endpoint descriptors for the interface. Some configurations also have class- or vendor-specific descriptors. This chapter has more on what the descriptors contain.

11. The host assigns and loads a device driver (except for composite devices). After learning about a device from its descriptors, the host looks for the best match in a driver to manage communications with the device. Windows hosts use INF files to identify the best match. The INF file may be a system file for a USB class or a vendor-provided file that contains the device’s Vendor ID and Product ID. Chapter 9 has more about selecting a driver.

For devices that have been enumerated previously, Windows may use stored information instead of searching the INF files. After the operating system assigns and loads the driver, the driver may request the device to resend descriptors or send other class-specific descriptors.

An exception to this sequence is composite devices, which can have different drivers assigned to multiple interfaces in a configuration. The host can assign these drivers only after enabling the interfaces, so the host must first configure the device as described below.



12. The host’s device driver selects a configuration. After learning about a device from the descriptors, the device driver requests a configuration by sending a Set Configuration request with the desired configuration number. Many devices support only one configuration. If a device supports multiple configurations, the driver can decide which configuration to request based on information the driver has about how the device will be used, or the driver can ask the user what to do or just select the first configuration. (Many drivers only select the first configuration.) On receiving the request, the device implements the requested configuration. The device is now in the Configured state and the device’s interface(s) are enabled.

For composite devices, the host can now assign drivers. As with other devices, the host uses the information retrieved from the device to find a driver for each active interface in the configuration. The device is then ready for use.

Hubs are also USB devices, and the host enumerates a newly attached hub in the same way as other devices. If the hub has devices attached, the host enumerates these after the hub informs the host of their presence.

Attached state. If the hub isn’t providing power to a device’s VBUS line, the device is in the Attached state. The absence of power may occur if the hub has detected an over-current condition or if the host requests the hub to remove power from the port. With no power on VBUS, the host and device can’t communicate, so from their perspective, the situation is the same as when the device isn’t attached.

Suspend State. A device enters the Suspend state after detecting no bus activity, including SOF markers, for at least 3 ms. In the Suspend state, the device should limit its use of bus power. Both configured and unconfigured devices must support this state. Chapter 16 has more about the Suspend state.

Wednesday, October 20, 2010

Things to know of spinlocks

Spin locks can be used in interrupt handlers, whereas semaphores cannot be used because they sleep
If a lock is used in an interrupt handler, you must also disable local interrupts (interrupt requests on the current processor) before obtaining the lock

So the pseudo code of spin lock

{
Disable preempt()
acquire_lock()
}

If used in ISR
{
Disable interrupts()
spin lock()
//critical region
spin_unlock()
}

OR

{
spinlock_t mr_lock = SPIN_LOCK_UNLOCKED;
unsigned long flags;

spin_lock_irqsave(&mr_lock, flags);
/* critical region ... */
spin_unlock_irqrestore(&mr_lock, flags);


}

The fact that a contended spin lock causes threads to spin (essentially wasting processor time) while waiting for the lock to become available is important. This behavior is the point of the spin lock. It is not wise to hold a spin lock for a long time. This is the nature of the spin lock: a lightweight single-holder lock that should be held for short durations. An alternative behavior when the lock is contended is to put the current thread to sleep and wake it up when it becomes available. Then the processor can go off and execute other code. This incurs a bit of overhead most notably the two context switches required to switch out of and back into the blocking thread, which is certainly a lot more code than the handful of lines used to implement a spin lock. Therefore, it is wise to hold spin locks for less than the duration of two context switches. Because most of us have better things to do than measure context switches, just try to hold the lock as little time as possible[1]. The semaphores provide a lock that makes the waiting thread sleep, rather than spin, when contended.

Method
Description

spin_lock()
Acquires given lock

spin_lock_irq()
Disables local interrupts and acquires given lock

spin_lock_irqsave()
Saves current state of local interrupts, disables local interrupts, and acquires given lock

spin_unlock()
Releases given lock

spin_unlock_irq()
Releases given lock and enables local interrupts

spin_unlock_irqrestore()
Releases given lock and restores local interrupts to given previous state

spin_lock_init()
Dynamically initializes given spinlock_t

spin_trylock()
Tries to acquire given lock; if unavailable, returns nonzero

spin_is_locked()
Returns nonzero if the given lock is currently acquired, otherwise it returns zero


certain locking precautions must be taken when working with bottom halves. The function spin_lock_bh() obtains the given lock and disables all bottom halves. The function spin_unlock_bh() performs the inverse.

Because a bottom half may preempt process context code, if data is shared between a bottom half process context, you must protect the data in process context with both a lock and the disabling of bottom halves. Likewise, because an interrupt handler may preempt a bottom half, if data is shared between an interrupt handler and a bottom half, you must both obtain the appropriate lock and disable interrupts.

Thursday, June 24, 2010

Kernel Directory Structure

Download: kernel.org
Browse: lxr.linux.no (with cross reference)
Directory structure
include: public headers
kernel: core kernel components (e.g., scheduler)
arch: hardware-dependent code
fs: file systems
mm: memory management
ipc: inter-process communication
drivers: device drivers
usr: user-space code
lib: common libraries

Monday, June 21, 2010

Adding a new system call

Assume we’d like add a system call calles “mycall” that takes two integers as input and return their sum.
1) Add “.long sys_mycall” at the end of the list in the file syscall_table.S.
---Full path for the file syscall_table.S is
usr/src/linux/arch/i386/kernel/syscall_table.S
NOTE: You can use the command sudo gedit syscall_table.S to edit the file
syscall_table.S. Beware that if you do not have the root privileges, system will not allow you to edit
any of the kernel files.
2) In file unistd.h
- Add #define __NR_mycall at the end of the list
(e.g. If the number of the last system call Last_System_Call_Num is 319 then the
line you shall add should be #define __NR_mycall 320.).
- Increment NR_syscalls by one (e.g. If before adding your system call total number of
system calls is 320, then this will be #define NR_syscalls 321.).
---Full path for the file unistd.h is /usr/src/linux/include/asm-i386/unistd.h
3) Add the following line at the end of the file syscalls.h:
asmlinkage long sys_mycall(int i, int j);
---Full path for the file syscalls.h is /usr/src/linux/include/linux/syscalls.h
4) Add mycall/ to core-y += in Makefile.
The line in the end shall look like:
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ mycall/
---Full path for Makefile is /usr/src/linux/Makefile.
5) Create a new directory in /usr/src/linux and name it mycall.
6) Create a new file called mycall.c in /usr/src/linux/mycall. Contents of the file shall be
as follows:
/*----------Start of mycall.c----------*/
#include <linux/linkage.h>
asmlinkage long sys_mycall(int i, int j) {
return(i+j);
}
/*-----------End of mycall.c-----------*/
*asmlinkage is used to look for the arguments on the kernel stack.
7) Create Makefile in /usr/src/linux/mycall. Makefile shall be like:
########## Start of Makefile ##########
obj-y := mycall.o
########## End of Makefile ##########
8) Create the following userspace program to test your system call and name it testmycall.c. The
contents of this file shall be:
/*---------- Start of testmycall.c File ----------*/
#include <unistd.h>
#include <stdio.h>
#define __NR_mycall
long mycall(int i, int j) {
return syscall(__NR_mycall, i, j);
};
int main() {
printf(“%d\n”, mycall(10, 20));
return 0;
}
/*---------- End of testmycall.c File ----------*/
9) Compile testmycall.c to test whether your system call works.
gcc testmycall.c –o testmycall

Tuesday, May 25, 2010

System call Internals

Try this link

Sytem Call Internals

Linux Linkers and Loaders

http://www.linuxjournal.com/article/6463

Creating a package using autoconf and automake

Please do refer this directly

http://mij.oltrelinux.com/devel/autoconf-automake/

In case this link does NOT turn up, use the following info
A tutorial for porting to autoconf & automake

l.u. 21/11/2005

A first disclaimer is that I don't really like autoconf and automake. This is not the place for longer dissertations, so I won't spend more words on this. However, it is a matter of facts that many users just like to fetch your application, and issue the usual ./configure && make && make install right ahead.
So, this is a synthetic tutorial for moving a Makefile-based program to an autohell- (this is a popular way to refer to { autoconf, automake, libtool } that I will encourage) enabled package.

A somewhat complete, likely example is given here. If your PRE is not exactly like the one proposed, you just probably won't need to perform the corresponding following steps.

Definition of the problem:

PRE: you have a tree with

* sources in src/
* documentation in doc/
* man pages in man/
* some scripts in scripts/ (in general, stuff to be installed but not compiled)
* examples in examples/

POST: you want to

* check for the availability of the needed headers/libraries
* possibly adjust some things (say some path in scripts, or in docimentation) at compile-time
* install everything in its adequate place

So, this is what to do for moving with the very minimum effort:

1. Cleaning up
Move away every possible Makefile you have in the package (rename it for now)
2. Generating configure.ac
Run autoscan:

$ autoscan

autoscan tries to produce a suitable configure.ac file (autoconf's driver) by performing simple analyses on the files in the package. This is enough for the moment (many people are just happy with it as permanent). Autoscan actually produces a configure.scan file, so let it have the name autoconf will look for:

$ mv configure.scan configure.ac

-- note: configure.in was the name used for autoconf files, now deprecated.
3. Adjusting things
Adjust the few things left to you by autoscan: open configure.ac with your favourite editor

$ vim configure.ac

look in the very first lines for the following:

AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)

and replace with your stuff, e.g.:

AC_INIT(pippo, 2.6, paperino@staff.pippo.org)

4. Generating a first configure script
At this point, you're ready to make autoconf produce the configure script:

$ autoconf

This produces two files: autom4te.cache and configure. The first one is a directory used for speeding up the job of autohell tools, and may be removed when releasing the package. The latter is the shell script called by final users.
In this status, what the configure script does is just checking for requirements as suggested by autoscan, so nothing very conclusive yet.
5. Generating suitable Makefiles
We have the system checking part. We now want the building and installing part. This is given by a cooperation of automake and autoconf. Automake generates some "templates" that autoconf-generated scripts will traduce into actual Makefile. A first, "main" automake file is needed in the root of the package:

$ vim Makefile.am

list the subdirectories where work is needed:

AUTOMAKE_OPTIONS = foreign
SUBDIRS = src doc examples man scripts

the first line sets the mode automake will behave like. "foreign" means not GNU, and is common for avoiding boring messages about files organized differently from what gnu expects.
The second line shows a list of subdirectories to descend for further work. The first one has stuff to compile, while the rest just needs installing, but we don't care in this file. We now prepare the Makefile.am file for each of these directories. Automake will step into each of them and produce the corresponding Makefile.in file. Those .in files will be used by autoconf scripts to produce the final Makefiles.
Edit src/Makefile.am:

$ vim src/Makefile.am

and insert:

# what flags you want to pass to the C compiler & linker
CFLAGS = --pedantic -Wall -std=c99 -O2
LDFLAGS =

# this lists the binaries to produce, the (non-PHONY, binary) targets in
# the previous manual Makefile
bin_PROGRAMS = targetbinary1 targetbinary2 [...] targetbinaryN
targetbinary1_SOURCES = targetbinary1.c myheader.h [...]
targetbinary2_SOURCES = targetbinary2.c
.
.
targetbinaryN_SOURCES = targetbinaryN.c

This was the most difficult one. In general, the uppercase, suffix part like "_PROGRAMS" is called primary and tells partially what to perform on the argument; the lowecase, prefix (it's not given a name) tells the directory where to install.
E.g.:

bin_PROGRAMS

installs binaries in $(PREFIX)/bin , and

sbin_PROGRAMS

installs in $(PREFIX)/sbin . More primaries will appear in the following, and here is a complete list of primaries. Not all can be prefixed to such primaries (see later for how to work around this problem).

Let us now move to mans:

$ vim man/Makefile.am

insert the following in it:

man_MANS = firstman.1 secondman.8 thirdman.3 [...]

yes, automake will deduce by itself what's needed for installing from this. Now edit for scripts:

$ vim scripts/Makefile.am

insert:

bin_SCRIPTS = script1.sh script2.sh [...]

The primary "SCRIPTS" instruct makefiles to just install the arguments, without compiling of course.

So far so good. Two jobs remain to define: installing examples and installing plain docs. This is the nasty part, as automake doesn't handle primaries for installing in the usual $(PREFIX)/share/doc/pippo . The workaround is to specify a further variable and using it as prefix:

$ vim doc/Makefile.am

docdir = $(datadir)/doc/@PACKAGE@
doc_DATA = README DONTS

if "abc" is wanted for prefix, "abcdir" is to be specified. E.g. the code above expands to /usr/local/share/doc/pippo ("@PACKAGE@" will be expanded by autoconf when producing the final Makefile, see below). $(datadir) is known by all configure scripts it generates. You may look for the list of directory variables.

Similarly for examples, but we want to install in $(PREFIX)/share/examples/pippo , so:

$ vim examples/Makefile.am

exampledir = $(datarootdir)/doc/@PACKAGE@
example_DATA = sample1.dat sample2.dat [...]

All these Makefile.am files now exist, but autoconf has now to be told about them.
6. Integrating the checking (autoconf) part and the building (automake) part
We insert now some macros in configure.ac for telling autoconf that the final Makefiles have to be produced after ./configure :

$ vim configure.ac

right after AC_INIT(), let initialize automake:

AM_INIT_AUTOMAKE(pippo, 2.6)

then, let autoconf generate a configure script that will output Makefiles for all of the above directories:

AC_OUTPUT(Makefile src/Makefile doc/Makefile examples/Makefile man/Makefile scripts/Makefile)

7. Making tools output the configure script and Makefile templates
we have now complete instructions for generating the famous configure script run by the users when installing, that both checks for building/running requirements and generates Makefiles for actually building and installing everything in place. Let now actually make tools generate such script:

$ aclocal

This generates a file aclocal.m4 that contains macros for automake things, e.g. AM_INIT_AUTOMAKE.

$ automake --add-missing

Automake now reads configure.ac and the top-level Makefile.am, interprets them (e.g. see further work has to be done in some subdirectories) and, for each Makefile.am produces a Makefile.in. The argument --add-missing tells automake to provide default scripts for reporting errors, installing etc, so it can be omitted in the next runs.
Finally, let autoconf build the configure script:

$ autoconf

This produces the final, full-featured configure shell script.
8. Further customizations
if you need to perform custom checks, or actions in configure, just write the (shell) code somewhere in configure.ac (before OUTPUT commands), then run autoconf again. For some checks, autoconf may already provide some macro: look in the list of autoconf macros before writing useless code.

How do things work from now on
The user first runs:

$ ./configure

The shell script just generated will:

1. scan for dependencies on the basis of the AC_* macros instructed in configure.ac. If there's something wrong/missing in the system, an opportune error message will be dumped.
2. for each Makefile requested in AC_OUTPUT(), translate the Makefile.in template for generating the final Makefile. The main makefile will provide the most common targets like install, clean, distclean, uninstall et al.

if configure succeeds, all the Makefile files are available. The user then issues:

$ make

The target all from the main Makefile will be worked. This target expands into all the hidden targets to first build what you requested. Then, by mean of

# make install

everything is installed.