分享到plurk 分享到twitter 分享到facebook

版本 ceb863cb08ffb2aafba9008cdb6abcc5bd58167b

rtenv-plus

HackPad 共筆<https://embedded2014.hackpad.com/Rtenv-plus-0VHEYKBpr3D>_

組員

楊震 / <Omar002<https://github.com/Omar002/rtenv-plus/>_>

丁士宸 / <Stanley Ding<https://github.com/StanleyDing/rtenv>_>

程政罡 / <marktwtn<https://github.com/marktwtn/rtenv-plus>_>

李昆憶 / <LanKuDot<https://github.com/LanKuDot/rtenv-plus>_>

鄭聖文 / <Shengwen<https://github.com/shengwen1997/>_>

作業系統架構

Context Switch

activate

  • 功能:將 kernel state push 到 Main stack 中,再將目前正在執行的 process state pop 到 register 中。

.. code-block:: c

activate:
 41     /* save kernel state */
 42     mrs ip, psr
 43     push {r4, r5, r6, r7, r8, r9, r10, r11, ip, lr}
 44     
 45     /* switch to process stack pointer */
 46     msr psp, r0                                                                                                                            
 47     mov r0, #3
 48     msr control, r0
 49     
 50     /* load user state */
 51     pop {r4, r5, r6, r7, r8, r9, r10, r11, lr}
 52     pop {r7}
 53 
 54     bx lr
  • 指令介紹:mrs Rd, PSRmsr PSR, Rd[1]_:Rd 為 general-purpose registers,PSR 可以為 psr、cpsr、apsr、msp、psp 等。 mrs Rd, PSR 可以將 PSR 的值寫到 Rd,而 msr PSR, Rd 則是將 Rd 值寫到 PSR 裡。

  • 運作:

    • L42,43:將 psr(program status register) 的值保存到 ip (r12) 裡,然後一同 push 到 main stack 裡。
    • L46:將 r0 所帶的值寫入到 psp (process stack pointer),注意呼叫 activate 所放的參數就是該 task 之 task_control_block 中 stack 的 address。
    • L47,48:將 control register 的值設為 3,藉此可以將 stack pointer 轉為指向 process stack (使 sp 值為 psp)。所以藉由 sp 可以存取其 stack 的內容。
    • L51:將 user_thread_stack 的 register 依序 pop 到 r4~r11 及lr,也是為何 user_thread_stack 的前9個 register 設計為 r4~r10、fp、_lr。
    • L52:再將 user_thread_stack_r7 pop 到 r7,達成傳遞 syscall 的功能。
    • 所以除了 r0~r3 及 ip、sp、pc、cpsr 之外,都被換成 user-mode 的 register 了。

init_task

  • 功能:將系統初始函式 first() 的位址放置到 process stack 的 lr 位置。藉由 activate 置換 process state 上來,可讓程式執行 first()

  • 運作:

.. code-block:: c

/* 傳入的參數為:欲執行 first() 的 task 的 stack位址 以及 first() 的位址 */
unsigned int *init_task(unsigned int *stack, void (*start)())
{
    /* 由於 stack 的設計為 full descendent stack,
     * 所以 stack pointer 一開始必須指向最高位址。
     * 觀察 user_thread_stack 的設計:r4 是最低位址,處在 stack 的底部
     * 而預期將 first() 的位址存到 _lr 中,所以必須 push 9個 word
     */
    stack += STACK_SIZE - 9;
    /* 利用 pointer arithmetic,可以將 first() 的位址存到 _lr 中:
     * user_thread_stack -> |r4 |r5 |r6 |r7 |r8 |r9 |r10|fp |_lr|...
     *             stack -> |[0]|[1]|[2]|[3]|[4]|[5]|[6]|[7]|[8]|...
     */
    stack[8] = (unsigned int)start;
    /* 回傳新的 sp 給該 task */
    return stack;
}

fork 原理

第一次進到 while loop

::

[ File: main.elf ]
while (1) { 
    tasks[current_task].stack = activate(tasks[current_task].stack);
333c:   f240 72a8   movw    r2, #1960   ; 0x7a8
...
3354:   681b        ldr r3, [r3, #0]
3356:   4618        mov r0, r3
3358:   f00e f8e2   bl  11520 <activate>    // 由此進入 activate,所以 LR 存的值是 0x335d
335c:   f240 72a8   movw    r2, #1960   ; 0x7a8
3360:   f2c2 0200   movt    r2, #8192   ; 0x2000
...
  • 進到 activate() 後,藉由 pop user state 到 register,將預先存好的 first() 的位址存到 LR 中。而原本的 LR 被 push 到 main stack 中,存有離開 activate() 後繼續執行的指令位址。

    ::

    [ 從 user_thread_stack pop 到 general-purpose registers ] user_thread_stack -> |r4 |r5 |r6 |r7 |r8 |r9 |r10|fp |_lr|… V 依 pop 順序到 register -> |R4 |R5 |R6 |R7 |R8 |R9 |R10|R11| LR|…

  • 利用 bx lr 使得程式轉往執行 first()。進到 first() 後,程式執行第一行的 fork()

    ::

    [ 程式執行 fork() ] void first() { 2f84: b580 push {r7, lr} 2f86: af00 add r7, sp, #0 if (!fork()) setpriority(0, 0), pathserver(); 2f88: f00e fb22 bl 115d0 // 由此進入 fork(),LR存的值為 0x2f8d 2f8c: 4603 mov r3, r0 2f8e: 2b00 cmp r3, #0

  • 在 syscall (這裡是fork) 中,會觸發 svc exception,程式轉往執行 SVC_Handler(),同時會 processor 會將 xPSR、PC、LR、R12、R3、R2、R1、R0[2]_依序 push 到目前的 stack 中 ( process stack ),被 push 到 process stack 的資訊中含有離開 fork() 後繼續執行的指令位址。

    ::

    [ 因為 Exception 所發生的 push register 到 stack ] user_thread_stack -> …|_r7|r0|r1|r2|r3|ip |lr|pc|xpsr|stack… 低位址 高位址 依 push 順序到 stack -> …….|R0|R1|R2|R3|R12|LR|PC|xPSR| ( _r7 存的是在 syscall 中被暫存的 R7 值 )

  • SVC_Handler() 中會將目前的 user state ( push 到 process stack ) 與 kernel state ( 從 main stack pop 出來 ) 作交換,此時 LR 擁有的位址為離開 activate() 後要執行的指令位址。所以離開 SVC_Handler() 後,程式會轉往執行 while loop,而在 SVC_Handler() 中,也將在 fork() 中存入 R7 的值 push 到 process stack 中了。所以接著會判定要進行 fork 動作。

進行fork

  • 將母 task 的 stack 內容複製到子 task 的 stack 中,但是母 task 的 r0 存的是目前產生的 task 數量,而子 task 則是 0。

硬體驅動原理

  • USB OTG</embedded/OTG>_

效能表現

參考資料

.. [1] mrs指令<http://infocenter.arm.com/help/topic/com.arm.doc.dui0489i/Cihjcedb.html>_ 、 msr指令<http://infocenter.arm.com/help/topic/com.arm.doc.dui0489i/Cihibbbh.html>_

.. [2] Cortex-M3 Exception<http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Babefdjc.html>_