Saturday, November 21, 2015

When does a Page Fault occur?

When does a Page Fault occur? Why ?




Page Fault generation




#include 
#include 
#include 
#include 
#include 

#define CHUNK_SIZE (20 * 1024 * 1024)
#define CHUNK_NUM 100
#define CHUNKS_COMMIT 7

int main(int arg, char **argv)
{
  int i,j;
  void *chunks[CHUNK_NUM];
  unsigned long totaltime = 0;
  
  printf("Program start\n");
 
  for (i=0; i



http://www.hanbit.co.kr/ebook/ebookmain.html

http://www.hanbit.co.kr/network/view.html?bi_id=1108

http://www.hanbit.co.kr/network/view.html?bi_id=1062

ARM Linux Interrupts Code Flow

ARM Vector Table vector_irq         -> Interrupt Dispatcher vector_dabt      -> Data Abort Dispatcher vector_pabt      -> Perfetch Abort Dispatcher vector_und       -> Undefined Instruction Dispatcher vector_fiq        -> Fast Interrupt Dispatcher vector_addrexcptn   -> Address Exception Dispatcher
Once an exception occurs , one of the above functions gets called.
IRQ Exceptions:
From there ,
/* Assembly Code */
vector_irq   ->> Depending on the ARM mode call the corresponding function
irq_svc
irq_handler
arch_irq_handler_default(arch/arm/kernel) ->> get_irqnr_preamble(arch/arm/mach-omap2) -> set Soc Specific irq base ->>  get_irqnr_and_base -> Check Pending Interrupts /* C Code */ asm_do_IRQ ->> routine called with r0 = irq number, r1 = struct pt_regs *
Data Aborts: Control Processor Register is CP15 DFSR & DFAR Register. vector_dabt(called from ROM code) ( __dabt_svc | __dabt_usr ) do_DataAbort ( do_translation_fault | do_page_fault | do_sect_fault | )
Prefetch Aborts: Control Processor Register is CP15 IFSR & IFAR Register. vector_pabt(called from ROM code) ( __pabt_svc | __pabt_usr ) do_PrefetchAbort ( do_translation_fault | do_page_fault | do_sect_fault | )
List of Instruction Faults static struct fsr_info fsr_info[] = {         { do_bad,               SIGBUS,  0,             "unknown 0"                     },         { do_bad,               SIGBUS,  0,             "unknown 1"                     },         { do_bad,               SIGBUS,  0,             "unknown 2"                     },         { do_bad,               SIGBUS,  0,             "unknown 3"                     },         { do_bad,               SIGBUS,  0,             "reserved translation fault"    },         { do_translation_fault, SIGSEGV, SEGV_MAPERR,   "level 1 translation fault"     },         { do_translation_fault, SIGSEGV, SEGV_MAPERR,   "level 2 translation fault"     },         { do_page_fault,        SIGSEGV, SEGV_MAPERR,   "level 3 translation fault"     },         { do_bad,               SIGBUS,  0,             "reserved access flag fault"    },         { do_bad,               SIGSEGV, SEGV_ACCERR,   "level 1 access flag fault"     },         { do_bad,               SIGSEGV, SEGV_ACCERR,   "level 2 access flag fault"     },         { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 3 access flag fault"     },         { do_bad,               SIGBUS,  0,             "reserved permission fault"     },         { do_bad,               SIGSEGV, SEGV_ACCERR,   "level 1 permission fault"      },         { do_sect_fault,        SIGSEGV, SEGV_ACCERR,   "level 2 permission fault"      },         { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 3 permission fault"      },         { do_bad,               SIGBUS,  0,             "synchronous external abort"    },         { do_bad,               SIGBUS,  0,             "asynchronous external abort"   },         { do_bad,               SIGBUS,  0,             "unknown 18"                    },         { do_bad,               SIGBUS,  0,             "unknown 19"                    },         { do_bad,               SIGBUS,  0,             "synchronous abort (translation table walk)" },         { do_bad,               SIGBUS,  0,             "synchronous abort (translation table walk)" },         { do_bad,               SIGBUS,  0,             "synchronous abort (translation table walk)" },         { do_bad,               SIGBUS,  0,             "synchronous abort (translation table walk)" },         { do_bad,               SIGBUS,  0,             "synchronous parity error"      },         { do_bad,               SIGBUS,  0,             "asynchronous parity error"     },         { do_bad,               SIGBUS,  0,             "unknown 26"                    },         { do_bad,               SIGBUS,  0,             "unknown 27"                    },         { do_bad,               SIGBUS,  0,             "synchronous parity error (translation table walk" },         { do_bad,               SIGBUS,  0,             "synchronous parity error (translation table walk" },         { do_bad,               SIGBUS,  0,             "synchronous parity error (translation table walk" },         { do_bad,               SIGBUS,  0,             "synchronous parity error (translation table walk" },         { do_bad,               SIGBUS,  0,             "unknown 32"                    },         { do_bad,               SIGBUS,  BUS_ADRALN,    "alignment fault"               },         { do_bad,               SIGBUS,  0,             "debug event"                   },         { do_bad,               SIGBUS,  0,             "unknown 35"                    },
        { do_bad,               SIGBUS,  0,             "unknown 36"                    },
        { do_bad,               SIGBUS,  0,             "unknown 37"                    },
        { do_bad,               SIGBUS,  0,             "unknown 38"                    },
        { do_bad,               SIGBUS,  0,             "unknown 39"                    },
        { do_bad,               SIGBUS,  0,             "unknown 40"                    },
        { do_bad,               SIGBUS,  0,             "unknown 41"                    },
        { do_bad,               SIGBUS,  0,             "unknown 42"                    },
        { do_bad,               SIGBUS,  0,             "unknown 43"                    },
        { do_bad,               SIGBUS,  0,             "unknown 44"                    },
        { do_bad,               SIGBUS,  0,             "unknown 45"                    },
        { do_bad,               SIGBUS,  0,             "unknown 46"                    },
        { do_bad,               SIGBUS,  0,             "unknown 47"                    },
        { do_bad,               SIGBUS,  0,             "unknown 48"                    },
        { do_bad,               SIGBUS,  0,             "unknown 49"                    },
        { do_bad,               SIGBUS,  0,             "unknown 50"                    },
        { do_bad,               SIGBUS,  0,             "unknown 51"                    },
        { do_bad,               SIGBUS,  0,             "implementation fault (lockdown abort)" },
        { do_bad,               SIGBUS,  0,             "unknown 53"                    },
        { do_bad,               SIGBUS,  0,             "unknown 54"                    },
        { do_bad,               SIGBUS,  0,             "unknown 55"                    },
        { do_bad,               SIGBUS,  0,             "unknown 56"                    },
        { do_bad,               SIGBUS,  0,             "unknown 57"                    },
        { do_bad,               SIGBUS,  0,             "implementation fault (coprocessor abort)" },
        { do_bad,               SIGBUS,  0,             "unknown 59"                    },
        { do_bad,               SIGBUS,  0,             "unknown 60"                    },
        { do_bad,               SIGBUS,  0,             "unknown 61"                    },
        { do_bad,               SIGBUS,  0,             "unknown 62"                    },
        { do_bad,               SIGBUS,  0,             "unknown 63"                    },
};

Interprocessor Interrupts

IPIs are used to maintain synchronisation between the processors. For example, if a kernel page table entry changes, both processors must either flush their TLBs or invalidate that particular page table entry. Whichever processor changed the mapping knows to do this automatically, but the other processor does not; therefore, the processor which changed the mapping must send an IPI to the other processor to tell it to flush its TLB or invalidate the page table entry.
Using the local APIC, you can send interrupts to all processors, all processors but the one sending the interrupt, or a specific processor or logical address as well as self-interrupts. To send an IPI, write the destination APIC ID, if needed, into the high word of the ICR, then write the low word of ICR with the destination shorthand and interrupt vector set to send the IPI. Be sure to wrap these functions in spinlocks. You might want to turn off interrupts as well while sending IPIs. 31  Private nIRQ - Each CPU only sees its own legacy nIRQ pin 30  Private watchdog - Each CPU has its own watchdog timer 29  Private timer - Each CPU has its own timer 28:16  Spare - available for future private peripherals 15:0    Private inter-processor interrupts - See below Inter-processor interrupts (IPI) can, for example, be used for interrupt-driven communication between CPUs in an SMP system. The GIC implements IPI using 16 software interrupts. To generate an IPI, an MPCore CPU must write to the primary GIC's Software Interrupt register specifying an interrupt ID in the range 0 to 15 and which CPU(s) will receive the interrupt.
Technique
Recommended for
Not recommended for
a) Uncached mappings
Infrequently or sparsely accessed DMA data blocks
Simplest implementation
Correctness/reliability
Intensively accessed DMA blocks will not benefit from caching, in which case performance can suffer.
b) Set affinity
Minimizing cache line migration overheads
In complex applications, a manual procedure will be required to map the IRQ part of device drivers and user processes to CPUs.  Thorough testing will be required.
In complex applications, the enforced mapping of processes to CPUs might mean that the maximum aggregate performance is not achievable due to unbalanced CPU loading.
c) Read for ownership
Small DMA data blocks.
Can be done by OS kernel
Large DMA data blocks – must read/write completely – will cause extra memory traffic and potentially thrash L1 cache.
d) Broadcast of cache maintenance operations
Can be done by OS kernel
Currently done by Linux 2.6.28-arm1
Small DMA blocks – overhead of synchronous IPI is likely to be significant.
Performance – scheduling of IPI depends on IRQ loading –  process blocks until all CPUs have responded.

Thursday, November 19, 2015

Monday, November 16, 2015

Saturday, November 14, 2015

QCOM RPM SMEM :)

Generic ARM debug modes and symbols and Address space maps ::



https://lwn.net/Articles/614224/

soc: qcom: Add device tree binding for SMEM
  soc: qcom: Add device tree binding for SMD
  mfd: devicetree: bindings: Add Qualcomm SMD based RPM DT binding
  soc: qcom: Add Shared Memory Manager driver
  soc: qcom: Add Shared Memory Driver
  mfd: qcom-smd-rpm: Driver for the Qualcomm RPM over SMD
  regulator: qcom-smd-rpm: Regulator driver for the Qualcomm RPM




Thursday, October 29, 2015

BARE METAL HA HA HA HA

Fundamentals ::: First stepping stones of making an embedded system. BARE METALS.
BARE METAL

METAL

http://www.wiki.xilinx.com/Linux+Drivers

IDEAS for future projects

OS development
- Applications:

Simple OS with scheduler algorithm.
When too many interrupts (or other stuff) -> does not respect deadlines, misses deadlines. 
When deadlines are missed for too long, the processor takes time to generate bitstream and program an external fpga (using foss tools) which implements some function accelerated in hw. 
Use http://yosefk.com/blog/how-fpgas-work-and-why-youll-buy-one.html to get inspired on which function to accelerate.
- Languages (for bare-metal development of OS):
Goes baremetal?

http://www.embedded.com/design/programming-languages-and-tools/4428704/2/Alternatives-to-C-C--for-system-programming-in-a-distributed-multicore-world

http://www.slideshare.net/xen_com_mgr/next-generation-cloud-rise-of-the-unikernel-v2-updated?next_slideshow=1

http://programmers.stackexchange.com/questions/274927/is-functional-language-without-runtime-written-in-c-possible

http://www.reddit.com/r/haskell/comments/29tgjd/ideal_programming_language_for_a_new_modern_os/

https://www.reddit.com/r/rust/comments/2web3t/is_rust_going_to_replace_cc_when_it_comes_to/

http://www.reddit.com/r/haskell/comments/2sahpi/why_no_embedded_systems/
- Projects:

http://repetae.net/computer/jhc/manual.html

https://zinc.rs/

Good for multicore?

http://www.embedded.com/design/programming-languages-and-tools/4438718/Programming-languages-for-multicore-systems-

- Very good reading:

Educating Embedded Systems Hackers:
https://www.kth.se/polopoly_fs/1.580282!/wese2014.pdf

http://elib.dlr.de/96449/1/Thesis_report_Wei_final.pdf
MULTICORE RASPI 2

https://www.raspberrypi.org/forums/viewtopic.php?f=72&t=98904&start=25
https://github.com/PeterLemon/RaspberryPi/tree/master/SMP/SMPINIT (smp)
OPENCORES:
- K7 Gtx sim model. 8b10 from opencores, what about rx_align?
- Rchitecture
EYE OPEN ON:
- opencl openmp for embedded
- xen hypervisor
- functional haskell/erlang/rust

ARM Linux Exception handlers implementation


Aborts Exception Handling

Aborts can be generated either on failed instruction fetches (prefetch aborts) or failed data accesses (data aborts). They can come from the external memory system giving an error response on a memory access (indicating perhaps that the specified address does not correspond to real memory in the system).
Alternatively, the abort can be generated by the Memory Management Unit (MMU) of the processor. An operating system can use MMU aborts to dynamically allocate memory to applications.

 Prefetch Abort Implementation


1. After getting prefetch abort exception, current mode PC will store in exception_LR and 
    CPSR into exception_SPSR, then PC will point to prefetch abort vector address.
        __vectors_start:
        ...
             W(b)    vector_pabt + stubs_offset
      
2. So when ARM refers to the vector table it follows the branch and lands up here. At this moment ARM is in Abort mode, IRQs are disabled, LR contains PC of when abort occurred and SPSR contains CPSR of when abort occurred. Since we are in abort mode, so r13 (SP) is banked, so load SP with address of a small stack frame (size of 3 words) that we have created at cpu_init(). This is abort exception stack  
     
    .macro  vector_stub, name, mode, correction=0
     vector_\name: (in this case vector_pabt)
   ...
   
        @
        @ Save r0, lr_ (parent PC) and spsr_
        @ (parent CPSR)
        @
        stmia   sp, {r0, lr}            @ save r0, lr
        mrs     lr, spsr
        str     lr, [sp, #8]            @ save spsr


        @
        @ Prepare for SVC32 mode.  IRQs remain disabled.
        @
        mrs     r0, cpsr
        eor     r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
        msr     spsr_cxsf, r0

        movs    pc, lr                  @ branch to handler in SVC mode

3. After this basic setup is done, depending on the mode, in which ARM was, when exception occurred
    we switch to specific handler. We'll assume that ARM was executing in SVC mode, so we'll look into the
    details of __pabt_svc

       /*
        * Prefetch abort dispatcher
        * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
        */
        vector_stub     pabt, ABT_MODE, 4

        .long   __pabt_usr                      @  0 (USR_26 / USR_32)
        .long   __pabt_invalid                  @  1 (FIQ_26 / FIQ_32)
        .long   __pabt_invalid                  @  2 (IRQ_26 / IRQ_32)
        .long   __pabt_svc                      @  3 (SVC_26 / SVC_32)

 4. __pabt_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 and saves them on SVC mode stack. After that it will call
     pabt_helper and increments the preempt count.
   
     _pabt_svc:
         svc_entry
         mov     r2, sp                          @ regs
         pabt_helper


5.
      .macro  pabt_helper
        @ PABORT handler takes pt_regs in r2, fault address in r4 and psr in r5
         
            #ifdef MULTI_PABORT
                     ldr     ip, .LCprocfns
                     mov     lr, pc
                     ldr     pc, [ip, #PROCESSOR_PABT_FUNC]
            #else
                     bl      CPU_PABORT_HANDLER
            #endif
      .endm

6.
     arch/arm/include/asm/glue-pf.h
     #define CPU_PABORT_HANDLER v7_pabort

     arch/arm/mm/pabort-v7.S
             .align  5
     ENTRY(v7_pabort)
             mrc     p15, 0, r0, c6, c0, 2           @ get IFAR
             mrc     p15, 0, r1, c5, c0, 1           @ get IFSR
             b       do_PrefetchAbort
     ENDPROC(v7_pabort)

7. here r0 contains Fault Addr Reg and r1 contains Fault Status Reg, based on status, respective function
    will be called

    arch/arm/mm/fault.c

    asmlinkage void __exception 
    do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)

    arch/arm/mm/fsr-2level.c
         static struct fsr_info ifsr_info[] = {
                  ...
                 { do_translation_fault, SIGSEGV, SEGV_MAPERR,   "section translation fault"        },
                 { do_bad,               SIGSEGV, SEGV_ACCERR,   "page access flag fault"           },
                 { do_page_fault,        SIGSEGV, SEGV_MAPERR,   "page translation fault"           },
                 { do_sect_fault,        SIGSEGV, SEGV_ACCERR,   "section permission fault"         },
                 { do_sect_fault,        SIGSEGV, SEGV_ACCERR,   "section permission fault"         },
                  ... 
         }

8. On error case will do Unhandled prefetch abort and broadcast die notification
   
          if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
                 return;
          printk(KERN_ALERT "Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n",
                inf->name, ifsr, addr);

          arm_notify_die("", regs, &info, ifsr, 0);

9. if we are in user mode will just send SIGSEGV and kill that process, or in SVC mode will trigger oops

    arch/arm/kernel/traps.c
          arm_notify_die:
                 if (user_mode(regs)) {
                       force_sig_info(info->si_signo, info, current);
                 } else {                
                      die(str, regs, err);
                 }

Data Abort Implementation


       Data abort and prefetch abort implementation is almost same. Only do_DataAbort() is get called.


Interrupt handler implementation

  • Interrupt Setup

  • 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.          

ARM Linux 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 arch/arm/kernel/entry-armV.S file):

__vectors_start:
 ARM(   swi     SYS_ERROR0      )
 THUMB( svc     #0              )
 THUMB( nop                     )
W(b)    vector_und + stubs_offset
W(ldr)  pc, .LCvswi + stubs_offset
W(b)    vector_pabt + stubs_offset
W(b)    vector_dabt + stubs_offset
W(b)    vector_addrexcptn + stubs_offset
W(b)    vector_irq + stubs_offset
W(b)    vector_fiq + stubs_offset

.globl  __vectors_end
__vectors_end:


/*
 * Vector stubs.
 *
 * This code is copied to 0xffff0200 so we can use branches in the
 * vectors, rather than ldr's.  Note that this code must not
 * exceed 0x300 bytes.
 *
 * Common stub entry macro:
 *   Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
 *
 * SP points to a minimal amount of processor-private memory, the address
 * of which is copied into r0 for the mode specific abort handler.
 */
.macro  vector_stub, name, mode, correction=0
.align  5

1. In our case vector_irq
vector_\name:
  
2.      .if \correction
sub     lr, lr, #\correction
.endif
3. So when ARM refers to the vector table it follows the branch and lands up here
   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 cpu_init().
   This stack is only used when we are in IRQ mode.

@
@ Save r0, lr_ (parent PC) and spsr_
@ (parent CPSR)
@
stmia   sp, {r0, lr}            @ save r0, lr
mrs     lr, spsr
str     lr, [sp, #8]            @ save spsr

4. We save LR_ and SPSR_ on the temporary IRQ stack and we switch to SVC mode
  
@
@ Prepare for SVC32 mode.  IRQs remain disabled.
@
mrs     r0, cpsr
eor     r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
msr     spsr_cxsf, r0

@
@ the branch table must immediately follow this code
@
and     lr, lr, #0x0f
 THUMB( adr     r0, 1f                  )
 THUMB( ldr     lr, [r0, lr, lsl #2]    )
mov     r0, sp
 ARM(   ldr     lr, [pc, lr, lsl #2]    )

5. 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

/*
 * Interrupt dispatcher
 */
vector_stub     irq, IRQ_MODE, 4

.long   __irq_usr                       @  0  (USR_26 / USR_32)
.long   __irq_invalid                   @  1  (FIQ_26 / FIQ_32)
.long   __irq_invalid                   @  2  (IRQ_26 / IRQ_32)
.long   __irq_svc                       @  3  (SVC_26 / SVC_32)

6. __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
   and saves them on SVC mode stack. After that it will call irq_handler and increments the preemt count.

__irq_svc:
svc_entry
irq_handler

#ifdef CONFIG_PREEMPT
get_thread_info tsk
ldr     r8, [tsk, #TI_PREEMPT]          @ get preempt count
ldr     r0, [tsk, #TI_FLAGS]            @ get flags
teq     r8, #0                          @ if preempt count != 0
movne   r0, #0                          @ force flags to 0
tst     r0, #_TIF_NEED_RESCHED
blne    svc_preempt
#endif

#ifdef CONFIG_TRACE_IRQFLAGS
@ The parent context IRQs must have been enabled to get here in
@ the first place, so there's no point checking the PSR I bit.
bl      trace_hardirqs_on
#endif
svc_exit r5                             @ return from exception
 UNWIND(.fnend          )
ENDPROC(__irq_svc)


7. After this arch specific handler get called.

/*
 * Interrupt handling.
 */
.macro  irq_handler
#ifdef CONFIG_MULTI_IRQ_HANDLER
ldr     r1, =handle_arch_irq
mov     r0, sp
adr     lr, BSYM(9997f)
ldr     pc, [r1]
#else
arch_irq_handler_default
#endif
9997:
.endm


8. For the SoCs which are using ARM GIC:

arch/arm/kernel/setup.c:
 handle_arch_irq = mdesc->handle_irq

   arch/arm/mach-ux500/board-mop500.c:
  .handle_irq     = gic_handle_irq,

arch/arm/kernel/irq.c:
  handle_IRQ:generic_handle_irq

kernel/irq/irqdesc.c:
  generic_handle_irq:generic_handle_irq_desc

include/linux/irqdesc.h:
  generic_handle_irq_desc:desc->handle_irq

9. handle_irq is the actual call for the flow handler which we registered as handle_fasteoi_irq

kernel/irq/chip.c
handle_fasteoi_irq:handle_irq_event

kernel/irq/handle.c
handle_irq_event:handle_irq_event_percpu

kernel/irq/handle.c
handle_irq_event_percpu

do {
res = action->handler(irq, action->dev_id);
action = action->next;
} while (action);  

Thursday, October 22, 2015

Page Table 64B

https://bwidawsk.net/blog/index.php/2014/07/future-ppgtt-part-4-dynamic-page-table-allocations-64-bit-address-space-gpu-mirroring-and-yeah-something-about-relocs-too/

https://lwn.net/Articles/106177/


Monday, October 12, 2015

TZ

TZ Tegra Master: http://nv-tegra.nvidia.com/gitweb/?p=3rdparty/ote_partner/tlk.git;a=shortlog;h=refs/heads/master


https://github.com/ARM-software/arm-trusted-firmware


http://www.slideshare.net/linaroorg/hkg15502-arm-trusted-firmware-evolution?related=1

http://ds.arm.com/developer-resources/sample-code/

Program execution flow

The flow of program execution is shown below:
  secureStart     startup_secure.s: Initialization of Secure world
       |
    __main        ARM library initialization
       |
     main         main_secure.c: Enable caches and configure TZPC
       |
  monitorInit     monitor.s: initialize Monitor
       |
     main         main_secure.c: Print message and execute SMC
       |
     S -> NS
       |
  normalStart     startup_normal.s: Initialization of Normal world
       |
    __main        ARM library initialization
       |
     main         main_normal.c: Enable caches, print message and execute SMC
       |
    NS -> S
       |
  SMC_Handler     monitor.s: Perform context switch from NS to S
       |
     main         main_secure.c: Print message and execute SMC
       |
  SMC_Handler     monitor.s: Perform context switch from S to NS
       |
     S -> NS
       |
     main         main_normal.c: Print message and execute SMC
       |
    NS -> S
       |
  SMC_Handler     monitor.s: Perform context switch from NS to S
       |
     main         main_secure.c: Print message and execute SMC

Article ::http://file.scirp.org/Html/7-9301356_18574.htm