F9 Kernel是一个实验性质的微内核实现,它受著名的L4微内核的启发,用来构建灵活的嵌入式系统。F9微内核开发的动机是运用最新的内核设计思想,在ARM Cortex-M系列微处理器上运行实时和分时应用程序(例如无线通信应用等),同时兼顾效率(性能+功耗)和安全性(内存保护+隔离执行)。它具备以下特点
- F9遵循了微内核的基本原则,它只在处理器特权模式中实现地址空间、线程管理和IPC通信机制.
- 为ARM Cortex-M系列设计和定制,支持NVIC(嵌套矢量中断控制器),位带,MPU(内存保护单元)。
- 高效的调度和tickless机制,允许ARM Cortex-M仅在需要时唤醒,无论是在预定的时间或中断事件。因此,它比使用系统计时器SysTick的常用方法产生更好的节能效果,后者需要一个不断运行的高频时钟。
- 支持KProbes机制,KProbes是一种受Linux内核启发的动态检测系统,它允许开发人员收集关于内核操作的额外信息,而无需重新编译或重新启动内核。它允许用代码插入内核中的位置,当ARM核心遇到探测点时,插入代码就会运行。一旦插装代码完成执行,内核将继续正常执行。
- 每个线程都有自己的TCB(线程控制块),并由其全局id寻址。dispatcher负责切换上下文。具有相同优先级的线程以循环方式执行。
- 内存管理方式有三种
- 内存池(Memory pool),它代表具有特定属性的物理地址空间区域。
- 灵活页( Flexible page),它描述了地址空间的一个总是大小对齐的区域。与其他L4实现不同,F9中的灵活页面代替了MPU区域。
- 地址空间(Address space),由这些灵活的页面组成。
- 提供系统调用用来管理地址空间
- Grant:将内存页授予给新用户,不能再被前用户使用.
- Map:这实现了共享内存——内存页被传递给另一个任务,但两个任务都可以使用.
- Flush:已映射给其他用户的内存页将从其地址空间中Flush.
- 关于用户线程和微内核之间的交互,正在采用UTCB(用户级线程控制块)的概念。UTCB是线程虚拟地址空间中的一个特定于线程的小区域,它总是被映射的。因此,对UTCB的访问永远不会引发页面错误,这使得内核能够很好地访问系统调用参数,特别是从/复制到用户线程的IPC有效负载。
- 内核提供了同步IPC(进程间通信),短IPC仅在CPU寄存器中携带有效负载,而完整的IPC通过通信双方的UTCBs复制消息有效负载。
- 支持内核调试和分析机制:
- 可配置调试控制台
- 内存转储
- 线程分析:名称、正常运行时间、已分配/当前/已使用的堆栈
- 内存分析:内核表,池空闲/已分配大小,碎片
开发板:
本环境使用的开发平台是STM32F407G-DISC1,它是stm32f4-discovery系列,主控为Cortex-M4F核,支持板载st-link调试器,开发板资源如下所述:
- STM32F407VGT6 in LQFP100 package
- ARM® 32-bit Cortex® -M4 CPU with FPU
- 168 MHz max CPU frequency
- 1 MB Flash
- 192+4 KB SRAM including 64-Kbyte of core coupled memory
- GPIO with external interrupt capability
- 3x12-bit ADC with 24 channels
- 2x12-bit D/A converters
- USART/UART (6)
- ......
STM32F4DISCOVERY Discovery有6个UARTs. 默认配置是115200 8N1. 需要留意的是 ST-Link Virtual Com Port is not wired to chip serial port. In order to enable console output you should use a serial cable and connect it to UART pins.
烧录说明,STM32F4DISCOVERY Discovery板载一个ST-LINK/V2调试器,它可以配合OPENOCD实现裸机烧录。
获取内核:
f9 kernel按照BSD开源协议托管在github上,内核不大,通过简单git clone命令即可完成下载.
git clone https://github.com/f9micro/f9-kernel.git
配置内核:
f9 kernel的构建环境依赖和linux相同,都是mconf,如果PC机之前有搭建linux的开发环境,则可以直接开发,否则,按照linux的开发标准安装依赖.
执行make config呼出类似于linux的menuconfig配置界面:
平台选择STM32F4,使用默认的串口(usart4),也就是板载的PA0和PA1 PIN脚,串口和pin脚的映射关系是:
编译内核:
配置完成后,退出配置菜单前点击保存配置.退出后,在控制台下直接执行make命令,即可编译内核:
执行make clean,清除编译中间文件和编译结果
如果想探查每个文件的编译细节,可以执行make V=1
根据上图的输出细节,可以看出,输出目标包括f9.elf,f9.elf.bin和f9.bin,其中f9.bin和f9.elf.bin是完全相同的,都是f9.elf对应的二进制文件.
烧录内核:
开发板支持USB模拟磁盘烧录方式,系统启动后,平台会在PC端模拟出一个磁盘,这时候可以将编译结果文件f9.bin拷贝到虚拟磁盘中,磁盘本身是虚拟的,拷贝过程其实就是烧录过程,拷贝结束后,重启,则启动烧录固件.除此之外,zephyr的west环境有对应的烧录工具,应该也支持烧录f9 kernel,后面可以一试,这里首先使用第一种磁盘烧录方式:
copy内核到虚拟磁盘完成烧录:
连接USB2TTL串口线到USART4(PA0,PA1),使用minicom观察启动时内核输出.
使用st-flash 烧录内核:
烧录:
st-flash write f9.bin 0x8000000
读取:
st-flash read firmware.bin 0x8000000 0x1000
擦除:
st-flash erase
基于zephyr环境的烧录和调试:
我们想利用zephyr的环境来烧录和调试f9 kernel,就先看一下zephyr是如何玩儿这块开发板的:
第一步:按照zephyr官方文档安装好zephyr开发环境,包括安装west,cmake,sdk tools,requirements.txt依赖以及下载代码.
第二步:需要安装elftools,否则编译DISCO1开发板工程会报错,不知道为什么requirements.txt没有列出安装,执行pip3 install pyelftools.
第三步:编译:
首先执行west build -t clean 清除上次编译结果文件
然后执行west build -b stm32f4_disco samples/basic/blinky,编译blinky项目,如下图:
第四步:烧录
zephyr烧录不依赖上面用到的虚拟磁盘机制,而是基于ocd和stlink.
连接好USB口,执行west flash
观察打印信息,注意,zephyr使用的串口和f9 kernel有所不同,zephyr使用串口usart2,也就是PA2/PA3.
第四步:调试
west build -b stm32f4_disco samples/hello_world
west flash
串口信息,固件已经烧录进去:
之后,执行west debug,调试helloworld程序