# 從無到有打造 IoT 作業系統核心:以 [Piko/RT](https://github.com/PikoRT/pikoRT) 為例 **Copyright (C) 2017 Jim Huang (黃敬群) <jserv.tw @ gmail.com>** ![](https://i.imgur.com/tbLQuVS.jpg) :::warning :warning: 注意 - 本系列講座全名為 Operating System Concepts And Renaissance [作業系統概念和文藝復興],簡稱 OSCAR。 ==[資料彙整在此](http://hackfoldr.org/oscar/)== ::: ## [Piko/RT](https://github.com/PikoRT/pikoRT) 的開發動機 * Y! 知識家 [台灣人發明的作業系統](https://tw.answers.yahoo.com/question/index?qid=20071204000010KK10989) * 「應該是找不到了,因為只發行了第一版就不行了」 * 為了破除「持久」的迷思,我們說什麼都要繼續 * 針對 ARM Cortex-M 系列,開發部分 POSIX 相容的作業系統核心 * 填補 FreeRTOS 和 (uc)Linux 之間的空缺 * FreeRTOS [精簡有力且平台移植眾多](http://wiki.csie.ncku.edu.tw/embedded/freertos),但缺乏有效的 POSIX 相容層 * Linux 已可在 ARM Cortex-M3/M4/M7 運作,但[需要投入各式改善工作](https://elinux.org/images/d/d4/Optimize_uClinux_for_ARM_Cortex-M4.pdf),核心加上 rootfs 往往逼近 2 MB 的空間 * 從 API 到核心機制仿效 Linux 的設計,重新針對 ARM Cortex-M3/M4/M7 實作 * Piko/RT 授權採用 [2-clause BSD](https://github.com/Piko-RT/pikoRT/blob/master/LICENSE) * 輕量級的 RTOS,允許既有應用程式移植 * [移植 MicroPython 的案例](https://github.com/Piko-RT/pikoRT/pull/16) * 作為 hypervisor for IoT 的驗證環境 * [形式化驗證](https://hackmd.io/s/H1xxp3pF0) 的對象 ## 相關專案 * [HyperC](http://socware.net/?page_id=18): 強者我前同事的大作,除了不是 open source 外,沒什麼好挑剔,高效能又精簡 * [F9 microkernel](https://github.com/f9micro): 針對 ARM Cortex-M + MPU 發展的微核心 * 商業運轉: [Genesi 的 IoTA 整套解決方案](https://genesi.company/solutions/embedded) * [rtenv+](http://wiki.csie.ncku.edu.tw/embedded/rtenv): 另一個在成功大學發展的作業系統核心,針對 ARM Cortex-M3/M4 發展 * [NuttX](http://nuttx.org/): 支援 POSIX 的完整 RTOS,已用於 [PX4 無人飛行器的韌體](https://github.com/PX4/Firmware) ## Linux 設計的演化 Linux 發展之初,只是一個以 single thread 為導向的作業系統,multi-threaded 與 SMP 也在發展 10 年後才納入,早期甚至得用彆腳的 LinuxThread 套件來實現 multi-threading,而 Mach 與 Hurd 在設計初期,就已經考慮這些需求。在 [NPTL](https://en.wikipedia.org/wiki/Native_POSIX_Thread_Library) 出現之前,Linux 的 multi-threaded 實做非常奇怪,仍然把 process 當作最基本的abstraction,也就是說 scheduling, context switch 等基本操作對象仍是 process,而thread / LWP 只是和別人分享定址空間和資源的 process。因此: * 用 clone() 產生的 thread 本質上仍是 process,可以說 Linux 核心中定義的 "thread" 只做到了資源共享,而不構成執行工作的最基本單位 * 嚴格來說,Linux 只實做了一半的 thread,但這並不是壞事,因為許多的應用程式不見得用到 thread,而且簡化 thread 實做的結果,使得 process 管理變得更有效率,副作用是產生出來的 "thread" 比其它作業系統的實做,顯得更 heavy-weight,可以說,過去 Linux 犧牲 thread 的效率,以換取 process 的效率 * 以 abstraction 的角度來看 Linux 過去並非在本質上支援 thread,但以 programming model 來看,Linux 的確是有 thread 可用,儘管效率較差 早期 Linux 的 process 和 thread 的效能和其他作業系統的客觀數據比較,可參照 Microsoft Research 論文 "[An Overview of the Singularity Project](http://research.microsoft.com/pubs/52716/tr-2005-135.pdf)" (2005 年) 的第 31 頁 ## API 涵蓋 以 [Minimal Real-time System Profile IEEE Std 1003.13](http://www.opengroup.org/austin/papers/wp-apis.txt) (PSE51) 為基礎 ``` POSIX RT ELC Feature PSE PSE PSE PSE Min Int Full FIPS UNIX LSB UNIX 51 52 53 54 SE SE SE 151-2 98 1.x 03 Processes - - X X - X X X X X X Pipes - - X X - X X X X X X Files and Directories - X - X - X X X X X X Basic I/O X X X X X X X X X X X Signals X X X X X X X X X X X Users and Groups - - - X - - X X X X X File Synchronization X X X X X X X - X X X Memory Mapped Files - X - X - X X - X X X Memory Protection - - X X - X X - X X X Process Priority - - X X - - - - o - o Scheduling Memory Locking X X X X - - - - o - o Synchronized I/O X X X X - - - - o - o Asynchronized I/O - X X X - X X - o o o Hi Resolution Clocks X X X X - - - - o - o & Timers Realtime Signals X X X X - - - - o - o Semaphores X X X X - - - - o - o Shared Memory X X X X - - - - o - o IPC Message Passing X X X X - - - - o - o Threads X X X X * * * - X o X Thread Safe Functions X X X X * * * - X - X Thread Attribute X X X X * * * - X - X Stack Address Thread Attribute X X X X * * * - X - X Stack Size Thread Process Shared - - X X * * * - X - X Thread Priority X X X X * * * - o - o Scheduling Thread Priority X X X X * * * - o - o Inheritence Thread Priority X X X X * * * - o - o Protection ``` 目標是運作以下程式: * [lmbench](http://www.bitmover.com/lmbench/) * Context switching * Signal handling * System call overhead * Memory read latency * [Cyclictest](https://wiki.linuxfoundation.org/realtime/documentation/howto/tools/cyclictest/start?s[]=cyclictest) * [hackbench](https://github.com/kosaki/hackbench) * [stress-ng](http://kernel.ubuntu.com/~cking/stress-ng/) * [PicoTCP](https://github.com/tass-belgium/picotcp) ## 仿效 Linux 的考量 * Linux kernel data structure * printk() * Process: fork() clone() exit() * Scheduler: preemption, sched_yeild() * semaphore, mutex, spinlock * timer * Wait queue * Interrupt: softirq, gen_irq * slab: malloc(), free() * mmap() * IO: char_dev(), block_dev() * File system: VFS, romfs, mtdram * pthread * device driver: serial(), tty ## 背景知識 - [Introduction: the ARM Cortex-M3 Exception / Interrupt](http://wiki.csie.ncku.edu.tw/embedded/arm-exceptions.pdf) - [ARM Cortex-M3](https://www.slideshare.net/GauravVerma3/arm-cortex-processor-compatibility-mode) - [STM32 程式開發:以 GNU Toolchain 為例](https://docs.google.com/document/d/1Ygl6cEGPXUffhTJE0K6B8zEtGmIuIdCjlZBkFlijUaE/edit) - [Build minimal ARM Kernel from Scratch](https://paper.dropbox.com/doc/9CQXvokHAXZSSlFMBp1t6) ## ARM Cortex-M 機制 首先我們先看到 ARM Cortex-M3的架構圖,今天我們要來介紹 M系列的特色之一 Nested Vectored Interrupt Controller (NVIC),我想大家比較熟悉的詞是 Nested Interrupts,也就是在 ISR時還有可能觸發其他的 IRQ,並且有機會可以搶佔現在的 ISR,而這個 Feature在早已存在在 Linux,但他是透過軟體來實現所謂的 Nested Interrupts,而 NVIC主要是透過硬體將原本軟體所想要的功能實作出來。 ![](https://i.imgur.com/rTas6qf.png) 注意到上面寫到支援 Interrupts的上限,和可支援的 Priority區間,這邊注意到這是官方給定的,但還是要由平台製造商(STMicro, NXP ...)決定。 ![](https://i.imgur.com/1t9HnZ8.png) 這邊特別補充一下 NVIC支援的 Priority,在即時系統裡,我們希望愈高 Priority的任務可以愈快得到回應或開始執行,這同理到 Interrupts上,照裡來說 Systick 的 Priority應該要比 UART RX還來得高,因為時間的更新是比較重要且這關係到任務的排程,所以高優先權的 Interrupt是可以 Preempt低優先權的 Interrupt。 介紹完 NVIC的特性之後我們可以開始介紹不同的 Exceptions了 ![](https://i.imgur.com/j1YCoHv.png) 注意到幾個欄位,分別是 Priority 和 Vector address,有一些 Interrupt 的 Priority是固定的,也有一些是 Configurable,再來是 Vector address,也就是他們相對應的 Handler在 Vector Table的 offset。 ### SVC 使用`svc`這個 instruction所啟動的 Interrupt,SVC是屬於 Synchronous Exception code: https://github.com/Piko-RT/pikoRT/blob/master/libc/piko/syscalls.S#L8 ### PendSV Interrupt-driven Supervisor-calling mechanism code: https://github.com/Piko-RT/pikoRT/blob/master/drivers/timer/systick.c#L110 ![](https://i.imgur.com/qQafS1B.png) ![](https://i.imgur.com/PdN5foX.png) ### HardFault, MemFault, UsageFault, BusFault code: https://github.com/Piko-RT/pikoRT/blob/master/arch/v7m-faults.c#L32 ![](https://i.imgur.com/xLoIu97.jpg) ### Tail-chaining 這是一個非常強大的機制,當現在處理的 Interrupt結束時,會去跟下一個 Interrupt的 Priority比較,如果沒有達到 Preemption的需求,他將會 trigger tail-chaining這個機制,核心概念就是當目前有其他的 interrupt pending,應該儘快處理下一個 interrupt而不必回去 user context。 ![](https://i.imgur.com/a5bmpW1.png) ### Late-arrival 這個機制就如同字面上的解釋,處理哪個 Interrupt可以在 Stacking之後再決定,所以 IRQ1 雖然比較晚到(優先權更高),但他卻可以先被處理。 ![](https://i.imgur.com/B2x9vpM.png) Reference: * - [Introduction: the ARM Cortex-M3 Exception / Interrupt](http://wiki.csie.ncku.edu.tw/embedded/arm-exceptions.pdf) * [A Beginner’s Guide on Interrupt Latency - and Interrupt Latency of the Arm Cortex-M processors](https://community.arm.com/processors/b/blog/posts/beginner-guide-on-interrupt-latency-and-interrupt-latency-of-the-arm-cortex-m-processors?CommentId=9cca204a-05eb-4ffb-8ead-dc4243e98f59) * [Using Cortex-M3/M4/M7 Fault Exceptions](http://www.keil.com/appnotes/files/apnt209.pdf) * [ARM® Cortex®‑M4 Processor Technical Reference Manual](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.100166_0001_00_en/index.html) ## CMSIS 有使用過嵌入式系統的朋友都知道有一種痛,叫作查 Reference Manual,不外乎就是找我要寫入或讀取哪個記憶體位置才能設定 Timer,這邊要特別注意的是從 0xA0000000 - 0xEFFFFFFF 其實是定址空間的範圍中,硬體暫存器對應的位址,也就是所謂的 Peripheral Register Mapping,以下是 M系列的 Memory Map ![](https://i.imgur.com/GlfHPyD.png) 而 Cortex Microcontroller Software Interface Standard (CMSIS)能幫我們省去這個麻煩,他有定義一系列的 Macro,讓我們使用,不僅如此,有了 CMSIS還能讓我們很輕鬆的 Porting到其他 M系列,以下是他的架構圖: ![](https://i.imgur.com/wt3pb34.png) 我們比較常使用的是 CMSIS-CORE這部份,它讓我們能更容易的操作 Peripheral Register code: https://github.com/Piko-RT/pikoRT/blob/master/target/stm32p103/init.c#L136 Reference: * [CMSIS-doc]http://www.keil.com/pack/doc/CMSIS/General/html/index.html ## STM32Cube HAL ![](https://i.imgur.com/uJQtc8Y.png) code: https://github.com/Piko-RT/pikoRT/blob/master/target/stm32f429/init.c#L32 Reference: * [STM32Cube-doc](http://www.keil.com/pack/doc/STM32Cube/General/html/index.html) ## Tool ``` 主要介紹這些工具在專案裡扮演什麼角色 ``` - [ ] [gef](https://github.com/hugsy/gef) - [ ] [gdb](https://www.gnu.org/software/gdb/) - [ ] [st-link](https://github.com/texane/stlink) - [ ] [openocd](http://openocd.org/) ## rtmutex ``` 從 PREEMPT_RT 切入 介紹 RT 是 uni kernel spin_lock 都換成 rtmutex 介紹 rtmutex 的 dependance pi-futex 簡介 可以考慮介紹 futex 特殊 feature PI-supported, lockdep 這兩個可以講很久是重點 ``` ![](https://i.imgur.com/TOZuR7G.png) ![](https://i.imgur.com/hCrx8HG.png) ![](https://i.imgur.com/HRHPnb7.png) * PI-chain * plist LWN: https://lwn.net/Articles/131299/ code: http://elixir.free-electrons.com/linux/latest/source/include/linux/plist.h#L85 雜亂的 tracing code: https://hackmd.io/GwMwHA7ARuCsC0UBMwDG8AsBDEATRsUADPNERAMx5KypGpA= Reference: * [PI-futex.txt](https://www.kernel.org/doc/Documentation/pi-futex.txt) * [rtmutex.txt](https://www.kernel.org/doc/Documentation/locking/rt-mutex.txt) * [rtmutex-design.txt](https://www.kernel.org/doc/Documentation/locking/rt-mutex-design.txt) ## tty ``` 沒辦法 只好從歷史開始 螢幕+鍵盤很貴 經過時間淬鍊 什麼都可以是 tty tty 變成app interface n_tty 專門來做 serialization 也就是從 tty接丟下去 serial core 低階interface 實際底層實作 ``` ![](https://i.imgur.com/22uATcI.png) ![](https://i.imgur.com/ZVCJdUj.png) Issue: https://github.com/Piko-RT/pikoRT/issues/14 Reference: * [Essential Linux Device Driver](https://doc.lagout.org/operating%20system%20/linux/Essential%20Linux%20Device%20Drivers.pdf) * [蝸窩科技 - tty framework](http://www.wowotech.net/sort/tty_framework) ## 我想幫忙,從哪裡下手? * 嘗試移植較精簡的程式,著手回報 * 案例: [MicroPython](https://github.com/Piko-RT/pikoRT/pull/16) * 測試、提交錯誤,協助分析: https://github.com/Piko-RT/pikoRT/issues * 幫忙撰寫技術文件、釐清程式碼行為和註解 * 拿來當作畢業專題和研究題目 (free support!)