RTEMS是一种开源的的基于GPLv2的实时操作系统,用作导弹弹载的实时操作系统。广泛运用在各类J事领域。本文基于RTEMS介绍如何构建运行RTEMS操作系统
为了获取源码,可以如下操作:
git clone https://gitlab.rtems.org/rtems/tools/rtems-source-builder.git git clone https://gitlab.rtems.org/rtems/rtos/rtems.git
代码拉下来之后,我们配置编译环境即可,如下:
# ./rtems-source-builder/source-builder/sb-set-builder --list-bsets | grep aarch64 6/rtems-aarch64.bset
我们基于aarch64进行构建,上述命令会拉取所有开发环境,需要等一会儿即可
# ./rtems-source-builder/source-builder/sb-set-builder --prefix=~/work/rtems/out/
结束后,我们验证gcc是否正常,如下:
# export PATH=$PATH:~/work/rtems/out/bin/ # aarch64-rtems6-gcc --version aarch64-rtems6-gcc (GCC) 13.3.0 20240521 (RTEMS 6, RSB b1aec32059aa0e86385ff75ec01daf93713fa382-modified, Newlib 1b3dcfd) Copyright (C) 2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
至此,环境搭建成功
此时我们进入rtems系统代码运行如下:
OUTPUT=~/rtems/rtems6/out/ ./waf configure --prefix=$OUTPUT
此时我们配置版型如下:
cat config.ini [aarch64/zynqmp_qemu] RTEMS_POSIX_API = True RTEMS_SMP = True
然后构建如下
./waf
安装如下
./waf install
rtems操作系统已经构建完成,我们通过zynqmp来实现qemu的构建。接下来我们测试运行rtems,如下
# rtems-run --rtems-bsps=zynqmp_qemu build/aarch64/zynqmp_qemu/testsuites/samples/hello.exe *** BEGIN OF TEST HELLO WORLD *** *** TEST VERSION: 6.0.0.87bf49b7156b9ddf45c218e5d4fa01f27b283db7 *** TEST STATE: EXPECTED_PASS *** TEST BUILD: RTEMS_POSIX_API RTEMS_SMP *** TEST TOOLS: 13.3.0 20240521 (RTEMS 6, RSB b1aec32059aa0e86385ff75ec01daf93713fa382-modified, Newlib 1b3dcfd) Hello World *** END OF TEST HELLO WORLD *** [ RTEMS shutdown ] CPU: 0 RTEMS version: 6.0.0.87bf49b7156b9ddf45c218e5d4fa01f27b283db7 RTEMS tools: 13.3.0 20240521 (RTEMS 6, RSB b1aec32059aa0e86385ff75ec01daf93713fa382-modified, Newlib 1b3dcfd) executing thread ID: 0x0a010001 executing thread name: UI1 Run time : 0:00:02.517420
如果通过qemu直接运行,可以如下指令
qemu-system-aarch64 -no-reboot -nographic -serial mon:stdio -machine xlnx-zcu102 -m 4096 -kernel build/aarch64/zynqmp_qemu/testsuites/samples/hello.exe
此时我们看到RTEMS会打印Hello World。一切正常,我们查看hello的task的源码如下
static rtems_task Init( rtems_task_argument ignored ) { rtems_print_printer_fprintf_putc(&rtems_test_printer); TEST_BEGIN(); printf( "Hello World\n" ); TEST_END(); rtems_test_exit( 0 ); }
可以发现,源码和行为一致
至此rtems的构建已完全完成
我们之前构建了RTEMS操作系统,这次继续构建此实时系统的应用程序,以hello kylin为例
为了编写应用程序以及管理,需要提前准备一个本地git仓库,如下
# mkdir -p app/hello # cd app/hello # git init .
waf作为rtems的构建工具,我们需要为应用程序下载此工具,如下:
# cp ../../waf . # git submodule add https://gitlab.rtems.org/rtems/tools/rtems_waf.git rtems_waf
编写应用前,需要为RTEMS操作系统提供init.c,如下
/* * Simple RTEMS configuration */ #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER #define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER #define CONFIGURE_UNLIMITED_OBJECTS #define CONFIGURE_UNIFIED_WORK_AREAS #define CONFIGURE_RTEMS_INIT_TASKS_TABLE #define CONFIGURE_INIT #include <rtems/confdefs.h>
然后创建hello.c应用程序如下
/* * Hello world example */ #include <rtems.h> #include <stdlib.h> #include <stdio.h> rtems_task Init( rtems_task_argument ignored ) { printf( "\nHello Kylin\n" ); exit( 0 ); }
最后为hello.c和init.c编写waf构建脚本,如下
# # Hello world Waf script # from __future__ import print_function rtems_version = "6" try: import rtems_waf.rtems as rtems except: print('error: no rtems_waf git submodule') import sys sys.exit(1) def init(ctx): rtems.init(ctx, version = rtems_version, long_commands = True) def bsp_configure(conf, arch_bsp): # Add BSP specific configuration checks pass def options(opt): rtems.options(opt) def configure(conf): rtems.configure(conf, bsp_configure = bsp_configure) def build(bld): rtems.build(bld) bld(features = 'c cprogram', target = 'hello.exe', cflags = '-g -O2', source = ['hello.c', 'init.c'])
此时一切准备完成之后,构建应用程序和构建操作系统的命令一致,如下:
# ./waf configure --rtems=~/work/rtems/out/ --rtems-bsp=aarch64/zynqmp_qemu # ./waf
通过rtems-run可以带起qemu运行应用程序,如下:
# rtems-run --rtems-bsps=zynqmp_qemu build/aarch64-rtems6-zynqmp_qemu/hello.exe
此时运行结果如下
RTEMS Testing - Run, 6.0.not_released Command Line: /root/work/rtems/out/bin/rtems-run --rtems-bsps=zynqmp_qemu build/aarch64-rtems6-zynqmp_qemu/hello.exe Host: Linux tf 6.8.0-47-generic #47-Ubuntu SMP PREEMPT_DYNAMIC Fri Sep 27 21:40:26 UTC 2024 x86_64 Python: 2.7.18 (default, Jan 31 2024, 16:23:13) [GCC 9.4.0] Host: Linux-6.8.0-47-generic-x86_64-with-Ubuntu-20.04-focal (Linux tf 6.8.0-47-generic #47-Ubuntu SMP PREEMPT_DYNAMIC Fri Sep 27 21:40:26 UTC 2024 x86_64 x86_64) Hello Kylin [ RTEMS shutdown ] CPU: 0 RTEMS version: 6.0.0.87bf49b7156b9ddf45c218e5d4fa01f27b283db7 RTEMS tools: 13.3.0 20240521 (RTEMS 6, RSB b1aec32059aa0e86385ff75ec01daf93713fa382-modified, Newlib 1b3dcfd) executing thread ID: 0x0a010001 executing thread name: UI1 Run time : 0:00:00.756775
至此,一个最简单的rtems的应用程序编写完成
最后提交相关代码即可
# git add init.c hello.c wscript # git commit -m "My first RTEMS application."
rtems可以支持capture任务的执行情况,如下演示效果
构建通过waf执行,如下
# ./waf configure --prefix=/root/work/rtems/out # ./waf
至此,我们可以运行capture示例如下
# qemu-system-aarch64 -no-reboot -nographic -s -serial mon:stdio -machine xlnx-zcu102 -m 4096 -kernel build/aarch64/zynqmp_qemu/testsuites/samples/capture.exe
此时的信息如下
*** BEGIN OF TEST CAPTURE ENGINE *** *** TEST VERSION: 6.0.0.87bf49b7156b9ddf45c218e5d4fa01f27b283db7-modified *** TEST STATE: USER_INPUT *** TEST BUILD: RTEMS_POSIX_API RTEMS_SMP *** TEST TOOLS: 13.3.0 20240521 (RTEMS 6, RSB b1aec32059aa0e86385ff75ec01daf93713fa382-modified, Newlib 1b3dcfd) Press any key to start capture engine (20s remaining) Press any key to start capture engine (19s remaining) Monitor ready, press enter to login. 1-rtems $
copen <buffer-size>: 此命令默认设置capture的buffersize byte单位 cwceil <priority-value>: 此命令过滤低于优先级的所有事件 cwfloor <priority-value>: 此命令过滤高于优先级的所有事件 cwglob <on/off>: 此命令启动或关闭监视器 ctset [-?] type [to name/id] [from] [from name/id]: 此命令设置触发器类型,这里RMON是监视自身 cenable: 此命令启用capture功能 cdisable: 此命令禁用capture功能 ctrace: 此命令trace出日志 cwadd <task-name>: 此命令为特定的任务添加监视 cwtctl <task-name> <on/off>: 此命令启动或禁用特定任务 ctlist: 此命令列出当前的task
此时我们进入captrue.exe,开启capture如下
1-rtems $ ctrace error: trace read failed: RTEMS_NOT_CONFIGURED 1-rtems $ 1-rtems $ cenable error: enable failed: RTEMS_UNSATISFIED 1-rtems $ copen 50000 capture engine opened. 1-rtems $ cwceil 100 watch ceiling is 100. 1-rtems $ cwfloor 102 watch floor is 102. 1-rtems $ cwglob on global watch enabled. 1-rtems $ ctset RMON trigger set. 1-rtems $ cenable capture engine enabled.
然后我们运行capture内置的测试程序test1,如下
1-rtems $ test1
等任务完成之后,我们关闭capture,然后查看trace如下
1-rtems $ cdisable capture engine disabled. 1-rtems $ ctrace 0 0:05:12.132637246 0a010003 CT1a 102 102 102 8192 TASK_RECORD 0 0:05:12.132782702 0 0a010003 CT1a 102 102 CREATED 0 0:05:12.133041342 258640 0a010003 CT1a 102 102 STARTED 0 0:05:12.133258110 216768 0a010003 CT1a 102 102 SWITCHED_IN 0 0:05:12.133502894 244784 0a010003 CT1a 102 102 BEGIN 0 0:05:12.134015374 512480 0a010003 CT1a 102 102 SWITCHED_OUT 0 0:05:13.130163838 0a010004 CT1b 101 101 101 8192 TASK_RECORD 0 0:05:13.130167454 996152080 0a010004 CT1b 101 101 CREATED 0 0:05:13.130238478 71024 0a010004 CT1b 101 101 STARTED 0 0:05:13.130302190 63712 0a010004 CT1b 101 101 SWITCHED_IN 0 0:05:13.130313246 11056 0a010004 CT1b 101 101 BEGIN 0 0:05:14.129783230 999469984 0a010004 CT1b 101 101 SWITCHED_OUT 0 0:05:14.129853182 0a010005 CT1c 100 100 100 8192 TASK_RECORD 0 0:05:14.129854974 71744 0a010005 CT1c 100 100 CREATED 0 0:05:14.129888638 33664 0a010005 CT1c 100 100 STARTED 0 0:05:14.129931806 43168 0a010005 CT1c 100 100 SWITCHED_IN 0 0:05:14.129936494 4688 0a010005 CT1c 100 100 BEGIN 0 0:05:14.130633246 696752 0a010005 CT1c 100 100 SWITCHED_OUT 0 0:05:14.130634638 1392 0a010004 CT1b 101 101 SWITCHED_IN 0 0:05:14.629816846 499182208 0a010004 CT1b 101 101 SWITCHED_OUT 0 0:05:14.629819598 2752 0a010003 CT1a 102 100 SWITCHED_IN 0 0:05:14.630445950 626352 0a010003 CT1a 102 102 SWITCHED_OUT
我们查看当前的任务列表,如下
1-rtems $ ctlist uptime: 0:22:34.490255513 total 2 09010001 IDLE 255 255 255 READY a--g 0a010002 RMON 1 1 1 READY a---
至此,capture的示例演示完成
rtems提供了trace的基本功能,如下演示此功能情况
对于rtems的trace功能,可以通过官方提供的fileio-trace.ini示例文件配置,如下
; ; RTEMS Trace Linker FileIO Trace Configuration ; ; Copyright 2015 Chris Johns <chrisj@rtems.org> ; ;-------------------------------------------------------------------------- [tracer] name = File IO tracer ; ; The configuration ; options = fileio-options traces = fileio defines = fileio enables = fileio triggers = fileio functions = fileio-funcs, rtems-api, rtems-posix, libc-heap include = rtems.ini, rtld-base.ini, rtld-trace-buffer.ini, libc-heap.ini ;-------------------------------------------------------------------------- [fileio-options] dump-on-error = true ; ; Tools ; prefix = /opt/rtems/4.11 rtems-path = /opt/rtems/kernel/4.11 rtems-bsp = sparc/sis ; ; Generator options. ; gen-enables = enable gen-triggers = enable ;-------------------------------------------------------------------------- [fileio] generator = trace-buffer-generator define = '#define RTLD_TRACE_BUFFER_SIZE (1UL * 1024 * 1024)' trace = rtems_shell_init trace = malloc, calloc, realloc, free traces = rtems-api-semaphore, rtems-posix-mutex enable = rtems_shell_init enable = malloc, calloc, realloc, free enables = rtems-api-semaphore, rtems-posix-mutex trigger = rtems_shell_init ;-------------------------------------------------------------------------- [fileio-funcs] headers = fileio-headers signatures = fileio-signatures [fileio-headers] header = '#include <rtems/shell.h>"' [fileio-signatures] rtems_shell_init = rtems_status_code, const char*, size_t, rtems_task_priority, const char*, bool, bool, rtems_shell_login_check_t
这里关于rtems-path和rtems-bsp主要配置为当前rtems的安装路径和bsp路径,如下
prefix = /root/work/rtems/out rtems-path = /root/work/rtems/out rtems-bsp = aarch64/zynqmp_qemu
这里以fileio为例,我们需要先将init.c编译成.o文件,如下
# /root/work/rtems/out/bin/aarch64-rtems6-gcc -MMD -Wall -Wmissing-prototypes -Wimplicit-function-declaration -Wstrict-prototypes -Wnested-externs -mno-outline-atomics -mcpu=cortex-a53 -mfix-cortex-a53-835769 -mfix-cortex-a53-843419 -O2 -g -fdata-sections -ffunction-sections -Icpukit/include -I../../../cpukit/include -Icpukit/score/cpu/aarch64/include -I../../../cpukit/score/cpu/aarch64/include -Ibsps/include -I../../../bsps/include -Ibsps/aarch64/include -I../../../bsps/aarch64/include -Ibsps/aarch64/xilinx-zynqmp/include -I../../../bsps/aarch64/xilinx-zynqmp/include -Itestsuites/support/include -I../../../testsuites/support/include ../../../testsuites/samples/fileio/init.c -c -o/root/work/rtems/rtems/build/aarch64/zynqmp_qemu/testsuites/samples/fileio/fileio-init.o -DHAVE_CONFIG_H=1 -DTEST_STATE_USER_INPUT=1
此命令来源于构建是waf的verbose参数,如下可以看到waf verbose参数. 值得注意的是,我将原来构建的init.c.672.o名字重写成了fileio-init.o
# rm -rf build/aarch64/zynqmp_qemu/testsuites/samples/fileio # ./waf -v Waf: Entering directory `/root/work/rtems/rtems/build' Waf: Leaving directory `/root/work/rtems/rtems/build' 'build' finished successfully (0.045s) Waf: Entering directory `/root/work/rtems/rtems/build/aarch64/zynqmp_qemu' 08:11:11 runner 'git ls-files --modified' 08:11:11 runner 'git rev-parse HEAD' [3710/4847] Compiling testsuites/samples/fileio/init.c 08:11:13 runner ['/root/work/rtems/out/bin/aarch64-rtems6-gcc', '-MMD', '-Wall', '-Wmissing-prototypes', '-Wimplicit-function- declaration', '-Wstrict-prototypes', '-Wnested-externs', '-mno-outline-atomics', '-mcpu=cortex-a53', '-mfix-cortex-a53-835769' , '-mfix-cortex-a53-843419', '-O2', '-g', '-fdata-sections', '-ffunction-sections', '-Icpukit/include', '-I../../../cpukit/inc lude', '-Icpukit/score/cpu/aarch64/include', '-I../../../cpukit/score/cpu/aarch64/include', '-Ibsps/include', '-I../../../bsps /include', '-Ibsps/aarch64/include', '-I../../../bsps/aarch64/include', '-Ibsps/aarch64/xilinx-zynqmp/include', '-I../../../bs ps/aarch64/xilinx-zynqmp/include', '-Itestsuites/support/include', '-I../../../testsuites/support/include', '../../../testsuit es/samples/fileio/init.c', '-c', '-o/root/work/rtems/rtems/build/aarch64/zynqmp_qemu/testsuites/samples/fileio/init.c.672.o', '-DHAVE_CONFIG_H=1', '-DTEST_STATE_USER_INPUT=1'] [4847/4847] Linking build/aarch64/zynqmp_qemu/testsuites/samples/fileio.exe 08:11:14 runner ['/root/work/rtems/out/bin/aarch64-rtems6-gcc', 'testsuites/samples/fileio/init.c.672.o', '-o/root/work/rtems/ rtems/build/aarch64/zynqmp_qemu/testsuites/samples/fileio.exe', '-Wl,-Bstatic', '-L.', '-lrtemscpu', '-lrtemsbsp', '-lrtemstes t', '-Wl,-Bdynamic', '-qrtems', '-mno-outline-atomics', '-mcpu=cortex-a53', '-mfix-cortex-a53-835769', '-mfix-cortex-a53-84341 9', '-Wl,--gc-sections', '-L/root/work/rtems/rtems/bsps/aarch64/shared/start', '-L/root/work/rtems/rtems/bsps/aarch64/xilinx-z ynqmp/start', '-Wl,--wrap=printf', '-Wl,--wrap=puts', '-Wl,--wrap=putchar'] Waf: Leaving directory `/root/work/rtems/rtems/build/aarch64/zynqmp_qemu' 'build_aarch64/zynqmp_qemu' finished successfully (2.606s)
根据抓到的日志信息,我们可以拿到ld的命令如下:
# /root/work/rtems/out/bin/aarch64-rtems6-gcc testsuites/samples/fileio/init.c.672.o -o/root/work/rtems/rtems/build/aarch64/zynqmp_qemu/testsuites/samples/fileio.exe -Wl,-Bstatic -L. -lrtemscpu -lrtemsbsp -lrtemstest -Wl,-Bdynamic -qrtems -mno-outline-atomics -mcpu=cortex-a53 -mfix-cortex-a53-835769 -mfix-cortex-a53-843419 -Wl,--gc-sections -L/root/work/rtems/rtems/bsps/aarch64/shared/start -L/root/work/rtems/rtems/bsps/aarch64/xilinx-zynqmp/start -Wl,--wrap=printf -Wl,--wrap=puts -Wl,--wrap=putchar
此时我们根据gcc的verbose参数,可以得到ld的调用参数如下
# aarch64-rtems6-ld -plugin /root/work/rtems/out/libexec/gcc/aarch64-rtems6/13.3.0/liblto_plugin.so -plugin-opt=/root/work/rtems/out/libexec/gcc/aarch64-rtems6/13.3.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccBjkjvt.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lrtemsbsp -plugin-opt=-pass-through=-lrtemscpu -plugin-opt=-pass-through=-latomic -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc -EL -X -maarch64elf --fix-cortex-a53-835769 --fix-cortex-a53-843419 -o /root/work/rtems/rtems/build/aarch64/zynqmp_qemu/testsuites/samples/fileio.exe /root/work/rtems/out/lib/gcc/aarch64-rtems6/13.3.0/nooa/a53/fix835769/fix843419/crti.o /root/work/rtems/out/lib/gcc/aarch64-rtems6/13.3.0/nooa/a53/fix835769/fix843419/crtbegin.o -L. -L/root/work/rtems/rtems/bsps/aarch64/shared/start -L/root/work/rtems/rtems/bsps/aarch64/xilinx-zynqmp/start -L/root/work/rtems/out/lib/gcc/aarch64-rtems6/13.3.0/nooa/a53/fix835769/fix843419 -L/root/work/rtems/out/lib/gcc/aarch64-rtems6/13.3.0/../../../../aarch64-rtems6/lib/nooa/a53/fix835769/fix843419 -L/root/work/rtems/out/lib/gcc/aarch64-rtems6/13.3.0 -L/root/work/rtems/out/lib/gcc/aarch64-rtems6/13.3.0/../../../../aarch64-rtems6/lib testsuites/samples/fileio/init.c.672.o -Bstatic -lrtemscpu -lrtemsbsp -lrtemstest -Bdynamic --gc-sections --wrap=printf --wrap=puts --wrap=putchar -lgcc --start-group -lrtemsbsp -lrtemscpu -latomic -lc -lgcc --end-group -lgcc /root/work/rtems/out/lib/gcc/aarch64-rtems6/13.3.0/nooa/a53/fix835769/fix843419/crtend.o /root/work/rtems/out/lib/gcc/aarch64-rtems6/13.3.0/nooa/a53/fix835769/fix843419/crtn.o -T linkcmds
这里清晰的描述了fileio.exe的ld过程,我们将其替换成rtems-tld的调用方式如下
# rtems-tld -C build/aarch64/zynqmp_qemu/fileio-trace.ini -- -B/root/work/rtems/out/aarch64-rtems6/zynqmp_qemu/lib -qrtems -mcpu=cortex-a53 -O2 -g -ffunction-sections -fdata-sections -Wall -Wmissing-prototypes -Wimplicit-function-declaration -Wstrict-prototypes -Wnested-externs -Wl,--gc-sections -mcpu=cortex-a53 -o /root/work/rtems/rtems/build/aarch64/zynqmp_qemu/testsuites/samples/fileio.exe /root/work/rtems/rtems/build/aarch64/zynqmp_qemu/testsuites/samples/fileio/fileio-init.o -lrtemstest
这里如果是通过ld链接,则系统无法进行trace,如果通过rtems-tld链接,则系统可被trace。效果如下
如果通过标准ld,如下验证
# qemu-system-aarch64 -no-reboot -nographic -s -serial mon:stdio -machine xlnx-zcu102 -m 4096 -kernel build/aarch64/zynqmp_qemu/testsuites/samples/fileio.exe *** BEGIN OF TEST FILE I/O *** *** TEST VERSION: 6.0.0.87bf49b7156b9ddf45c218e5d4fa01f27b283db7 *** TEST STATE: USER_INPUT *** TEST BUILD: RTEMS_POSIX_API RTEMS_SMP *** TEST TOOLS: 13.3.0 20240521 (RTEMS 6, RSB b1aec32059aa0e86385ff75ec01daf93713fa382-modified, Newlib 1b3dcfd) Press any key to start file I/O sample (20s remaining) ========================= RTEMS FILE I/O Test Menu ========================= p -> part_table_initialize f -> mount all disks in fs_table l -> list file r -> read file w -> write file s -> start shell Enter your selection ==>s Creating /etc/passwd and group with four useable accounts: root/pwd test/pwd rtems/NO PASSWORD chroot/NO PASSWORD Only the root user has access to all available commands. ========================= starting shell ========================= Welcome to rtems-6.0.0 (AArch64/AArch64-LP64/zynqmp_qemu) Copyright (C) 1989, 2021 RTEMS Project and contributors Login into RTEMS /dev/foobar login: root Password: RTEMS Shell on /dev/foobar. Use 'help' to list commands. SHLL [/] # rtrace status No trace buffer generated code in the application; see rtems-tld
此时我们rtrace status无法看到trace buffer,故此系统无法trace
我们通过rtems-tld链接的系统,如下现象
# qemu-system-aarch64 -no-reboot -nographic -s -serial mon:stdio -machine xlnx-zcu102 -m 4096 -kernel build/aarch64/zynqmp_qemu/testsuites/samples/fileio.exe *** BEGIN OF TEST FILE I/O *** *** TEST VERSION: 6.0.0.87bf49b7156b9ddf45c218e5d4fa01f27b283db7 *** TEST STATE: USER_INPUT *** TEST BUILD: RTEMS_POSIX_API RTEMS_SMP *** TEST TOOLS: 13.3.0 20240521 (RTEMS 6, RSB b1aec32059aa0e86385ff75ec01daf93713fa382-modified, Newlib 1b3dcfd) Press any key to start file I/O sample (20s remaining) Press any key to start file I/O sample (19s remaining) ========================= RTEMS FILE I/O Test Menu ========================= p -> part_table_initialize f -> mount all disks in fs_table l -> list file r -> read file w -> write file s -> start shell Enter your selection ==>s Creating /etc/passwd and group with four useable accounts: root/pwd test/pwd rtems/NO PASSWORD chroot/NO PASSWORD Only the root user has access to all available commands. ========================= starting shell ========================= Welcome to rtems-6.0.0 (AArch64/AArch64-LP64/zynqmp_qemu) Copyright (C) 1989, 2021 RTEMS Project and contributors Login into RTEMS /dev/foobar login: root Password: RTEMS Shell on /dev/foobar. Use 'help' to list commands. SHLL [/] # rtrace status RTEMS Trace Bufferring: status Running: yes Triggered: yes Level: 0% Traces: 24 SHLL [/] #
此时我们可以看到rtrace的状态
至此,我们开启了rtems的trace系统。需要备注的是rtems的默认账号密码是root/pwd
为了更清楚的了解rtems的shell功能,这里以两个例子来演示shell功能。
根据login_check中的rtems_shell_login_check函数,可以发现通过getpwnam_r获取passwd,这里实际调用是getpw_r,如下:
static int getpw_r( const char *name, int uid, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result ) { FILE *fp; int match; _libcsupport_pwdgrp_init(); if ((fp = fopen("/etc/passwd", "r")) == NULL) rtems_set_errno_and_return_minus_one( EINVAL ); for(;;) { if (!_libcsupport_scanpw(fp, pwd, buffer, bufsize)) goto error_einval; if (name) { match = (strcmp(pwd->pw_name, name) == 0); } else { match = (pwd->pw_uid == uid); } if (match) { fclose(fp); *result = pwd; return 0; } } error_einval: fclose(fp); rtems_set_errno_and_return_minus_one( EINVAL ); }
所以我们知道rtems的账号信息在passwd文件,我们可以在Init中发现其创建了此文件
writeFile( "/etc/passwd", 0644, "root:$6$$FuPOhnllx6lhW2qqlnmWvZQLJ8Thr/09I7ESTdb9VbnTOn5.65" "/Vh2Mqa6FoKXwT0nHS/O7F0KfrDc6Svb/sH.:0:0:root::/:/bin/sh\n" "rtems::1:1:RTEMS Application::/:/bin/sh\n" "test:$1$$oPu1Xt2Pw0ngIc7LyDHqu1:2:2:test account::/:/bin/sh\n" "tty:*:3:3:tty owner::/:/bin/false\n" "chroot::4:2:chroot account::/chroot:/bin/sh\n" );
这里可以发现,如果我们新增一个用户,则在这里写入信息即可。需要注意的是密码被加密了。我们需要留意加密方式代码如下
crypt_add_format(&crypt_md5_format); crypt_add_format(&crypt_sha512_format); struct crypt_format crypt_md5_format = CRYPT_FORMAT_INITIALIZER(crypt_md5_r, "$1$"); struct crypt_format crypt_sha512_format = CRYPT_FORMAT_INITIALIZER(crypt_sha512_r, "$6$");
也就是我们可以通过md5和sha512两种方式加密
通过python3我们可以测试如下,假设我们设置密码是kylinos,则
>>> print(crypt.crypt("kylinos", "$1$")) $1$$PZwUkYqm0zRLtkgaIFzoq/ >>> print(crypt.crypt("kylinos", "$6$")) $6$$FXse0c1.Rfb8DWjwHmjUZNzufS4shiUUIVwzonK6LcfAlEWAYXPyxwfZhjV0C5.7tlU/ZUgh5e8GI2MPo7W02.
所以我们可以为rtems设置两个账户,一个是rtems,使用md5加密,一个是kylin,使用sha512加密
diff --git a/testsuites/samples/fileio/init.c b/testsuites/samples/fileio/init.c index 084d54d81a..a8e95874ef 100644 --- a/testsuites/samples/fileio/init.c +++ b/testsuites/samples/fileio/init.c @@ -584,10 +584,11 @@ static void fileio_start_shell(void) 0644, "root:$6$$FuPOhnllx6lhW2qqlnmWvZQLJ8Thr/09I7ESTdb9VbnTOn5.65" "/Vh2Mqa6FoKXwT0nHS/O7F0KfrDc6Svb/sH.:0:0:root::/:/bin/sh\n" - "rtems::1:1:RTEMS Application::/:/bin/sh\n" + "rtems:$1$$PZwUkYqm0zRLtkgaIFzoq/:1:1:RTEMS Application::/:/bin/sh\n" "test:$1$$oPu1Xt2Pw0ngIc7LyDHqu1:2:2:test account::/:/bin/sh\n" "tty:*:3:3:tty owner::/:/bin/false\n" "chroot::4:2:chroot account::/chroot:/bin/sh\n" + "kylin:$6$$FXse0c1.Rfb8DWjwHmjUZNzufS4shiUUIVwzonK6LcfAlEWAYXPyxwfZhjV0C5.7tlU/ZUgh5e8GI2MPo7W02.:5:5:KylinOS User::/:/bin/sh\n" );
构建验证即可。可以确认kylin 和 rtems两个账户的密码 kylinos都能登录。
为了使得rtems支持shell脚本执行,我们需要按照joel的方式编写脚本。我们可以在Init中通过writeScript和rtems_shell_write_file写入shell文件,如下
+ writeScript( + "/kylin", + "#! joel\n" + "echo Hello KylinOS\n" + ); + + rtems_shell_write_file( + "/kylin1", + "#! joel\n" + "echo Hello KylinOS\n" + );
编译后,运行如下:
SHLL [/] # ./kylin Hello KylinOS SHLL [/] # ./kylin1 Unable to execute //kylin1
可以发现rtems_shell_write_file的文件,及时内容正确,但是无法运行,我们需要为其添加权限,如下
SHLL [/] # chmod 0777 /kylin1 SHLL [/] # ./kylin1 Hello KylinOS
为了内置rtems的命令,可以通过自己实现命令的方式,主要如下:
首先我们添加一个c文件,用作kylin命令,路径为cpukit/libmisc/shell/main_kylin.c内容为:
static int rtems_shell_main_kylin(int argc, char *argv[]) { printf("Kylin Say: Hello World!\n"); return 0; } rtems_shell_cmd_t rtems_shell_KYLIN_Command = { "kylin", /* name */ "kylin # show message", /* usage */ "system1", /* topic */ rtems_shell_main_kylin , /* command */ NULL, /* alias */ NULL /* next */ };
然后我们为其增加到cmd初始化的数组中,改动如下:
diff --git a/cpukit/include/rtems/shellconfig.h b/cpukit/include/rtems/shellconfig.h index 489f281400..2b51967f7b 100644 --- a/cpukit/include/rtems/shellconfig.h +++ b/cpukit/include/rtems/shellconfig.h @@ -95,6 +95,7 @@ extern rtems_shell_cmd_t rtems_shell_HEXDUMP_Command; extern rtems_shell_cmd_t rtems_shell_DEBUGRFS_Command; extern rtems_shell_cmd_t rtems_shell_DF_Command; extern rtems_shell_cmd_t rtems_shell_MD5_Command; +extern rtems_shell_cmd_t rtems_shell_KYLIN_Command; extern rtems_shell_cmd_t rtems_shell_RTC_Command; extern rtems_shell_cmd_t rtems_shell_SPI_Command; @@ -606,6 +607,7 @@ extern rtems_shell_alias_t * const rtems_shell_Initial_aliases[]; #if defined(CONFIGURE_SHELL_USER_COMMANDS) CONFIGURE_SHELL_USER_COMMANDS, #endif + &rtems_shell_KYLIN_Command, NULL };
最后我们添加kylin命令的编译,如下
diff --git a/spec/build/cpukit/objshell.yml b/spec/build/cpukit/objshell.yml index 2eaf4e17cf..09fdbaab8a 100644 --- a/spec/build/cpukit/objshell.yml +++ b/spec/build/cpukit/objshell.yml @@ -38,6 +38,7 @@ source: - cpukit/libmisc/shell/main_chdir.c - cpukit/libmisc/shell/main_chmod.c - cpukit/libmisc/shell/main_chroot.c +- cpukit/libmisc/shell/main_kylin.c - cpukit/libmisc/shell/main_cmdchmod.c - cpukit/libmisc/shell/main_cmdchown.c - cpukit/libmisc/shell/main_cmdls.c
编译运行后,我们可以直接调用kylin命令如下:
SHLL [/] # kylin Kylin Say: Hello World!