9.11. Creating a new Application¶
Contents
9.11.1. What is a WooKey application?¶
An application is a standalone software embedding all the needed content (apart from the application loader) and built on top of the EwoK microkernel. Applications interact with EwoK through syscalls.
Usually, libraries (such as the standard library) wrap such syscalls exposing higher level helpers. Applications can also interact with the hardware if they are allowed to (see the permissions model), and must initialize devices using dedicated syscalls. Higher level helpers for hardware interactions are also provided to the application in the form of userland drivers libraries (such as the USART library).
An application can use any of the SoCs, boards, cores and drivers sources to be able to run on the target.
9.11.2. The application source directory structure¶
A typical application named myapp is hosted in apps/myapp.
The application directory structure is composed of four main elements:
- Its Makefile
- Its configuration file (named Kconfig)
- Its main.c source file (usually hosted in src/ relative directory)
- a README.md file, describing the purpose of the application
And that should be all!
The myapp directory should look like this:
./src/main.c ./Kconfig ./Makefile ./README.md
9.11.3. Writing your first basic application¶
9.11.3.1. The application Makefile¶
The application Makefile allows to specify which library is needed by the application. The Makefile is also the link between the SDK and the application.
All applications Makefiles are nearly identical. Only the application’s dependencies (libs, drivers) and paths varies.
Here is a sample Makefile for a given application:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | ###################################################################
# About the application name and path
###################################################################
# Application name, can be suffixed by the SDK
APP_NAME ?= crypto
# application build directory name
DIR_NAME := crypto
# project root directory, relative to app dir
PROJ_FILES = ../../
# binary, hex and elf file names
BIN_NAME = $(APP_NAME).bin
HEX_NAME = $(APP_NAME).hex
ELF_NAME = $(APP_NAME).elf
# SDK helper Makefiles inclusion
-include $(PROJ_FILES)/m_config.mk
-include $(PROJ_FILES)/m_generic.mk
# application build directory, relative to the SDK BUILD_DIR environment
# variable.
APP_BUILD_DIR = $(BUILD_DIR)/apps/$(DIR_NAME)
###################################################################
# About the compilation flags
###################################################################
# Application CFLAGS, first yours... Remember no use '+=' as the SDK
# create an initial CLFAGS value for application
CFLAGS += -Isrc/ -Iinc/ -MMD -MP
# and the SDK ones
CFLAGS += $(APPS_CFLAGS)
###################################################################
# About the link step
###################################################################
# the layout file, must be named 'myapp.fw1.ld' for default. is overriden by
# the SDK in multi-bank case.
# this is an option of the linker.
EXTRA_LDFLAGS ?= -Tpin.fw1.ld
# linker options to add the layout file
LDFLAGS += $(EXTRA_LDFLAGS) -L$(APP_BUILD_DIR)
# generic linker options
LDFLAGS += $(AFLAGS) -fno-builtin -nostdlib -nostartfiles
# project's library/drivers you whish to use..., dont forget to add your application
# build directory as library source path (-L argument)
LD_LIBS += -lcryp -laes -lstd -L$(APP_BUILD_DIR)
###################################################################
# okay let's list our source files and generated files now
###################################################################
CSRC_DIR = src
SRC = $(wildcard $(CSRC_DIR)/*.c)
OBJ = $(patsubst %.c,$(APP_BUILD_DIR)/%.o,$(SRC))
DEP = $(OBJ:.o=.d)
# the output directories, that will be deleted by the distclean target
OUT_DIRS = $(dir $(OBJ))
# the ldcript file generated by the SDK
LDSCRIPT_NAME = $(APP_BUILD_DIR)/$(APP_NAME).ld
# file to (dist)clean
# first, objects and compilation related
TODEL_CLEAN += $(OBJ) $(DEP) $(LDSCRIPT_NAME)
# the overall target content
TODEL_DISTCLEAN += $(APP_BUILD_DIR)
.PHONY: app
#############################################################
# Informations about the applications
#############################################################
show:
@echo
@echo "\t\tAPP_BUILD_DIR\t=> " $(APP_BUILD_DIR)
@echo
@echo "C sources files:"
@echo "\t\tSRC\t=> " $(SRC)
@echo "\t\tASM\t=> " $(ASM)
@echo "\t\tOBJ\t=> " $(OBJ)
@echo "\t\tDEP\t=> " $(DEP)
@echo
@echo "\t\tCFLAGS\t=> " $(CFLAGS)
@echo "\t\tLDLAGS\t=> " $(LDLAGS)
###################################################################
# build targets (driver, core, SoC, Board... and local)
###################################################################
# all (default) build the app
all: $(APP_BUILD_DIR) alldeps app
############################################################
# eplicit dependency on the application libs and drivers
# compiling the application requires the compilation of its
# dependencies
# This permit to compile all the application dependencies
# when requesting the application compilation
############################################################
# library dependencies, here we have 2 libs
LIBDEP := $(BUILD_DIR)/libs/libstd/libstd.a \
$(BUILD_DIR)/libs/libaes/libaes.a
libdep: $(LIBDEP)
$(LIBDEP):
$(Q)$(MAKE) -C $(PROJ_FILES)libs/$(patsubst lib%.a,%,$(notdir $@))
# drivers dependencies, here only one
SOCDRVDEP := $(BUILD_DIR)/drivers/libcryp/libcryp.a
socdrvdep: $(SOCDRVDEP)
$(SOCDRVDEP):
$(Q)$(MAKE) -C $(PROJ_FILES)drivers/socs/$(SOC)/$(patsubst lib%.a,%,$(notdir $@))
# board drivers dependencies. If none, leave the variable empty
BRDDRVDEP :=
brddrvdep: $(BRDDRVDEP)
$(BRDDRVDEP):
$(Q)$(MAKE) -C $(PROJ_FILES)drivers/boards/$(BOARD)/$(patsubst lib%.a,%,$(notdir $@))
# external dependencies
EXTDEP :=
extdep: $(EXTDEP)
$(EXTDEP):
$(Q)$(MAKE) -C $(PROJ_FILES)externals
# alldeps, including all dependencies (see 'all' target, which depends on it)
alldeps: libdep socdrvdep brddrvdep extdep
###################################################################
# build targets (driver, core, SoC, Board... and local)
###################################################################
# app build the hex and elf binaries
app: $(APP_BUILD_DIR)/$(ELF_NAME) $(APP_BUILD_DIR)/$(HEX_NAME)
# objet files and dependencies
$(APP_BUILD_DIR)/%.o: %.c
$(call if_changed,cc_o_c)
# ELF file dependencies. libs are build separately and before.
# Be sure to add the libs to your config file!
$(APP_BUILD_DIR)/$(ELF_NAME): $(OBJ)
$(call if_changed,link_o_target)
# same for hex
$(APP_BUILD_DIR)/$(HEX_NAME): $(APP_BUILD_DIR)/$(ELF_NAME)
$(call if_changed,objcopy_ihex)
# same for bin. bin is not build but you can add it if you whish
$(APP_BUILD_DIR)/$(BIN_NAME): $(APP_BUILD_DIR)/$(ELF_NAME)
$(call if_changed,objcopy_bin)
# special target to create the application build directory
$(APP_BUILD_DIR):
$(call cmd,mkdir)
# including automaticaly calculated headers/sources dependencies
-include $(DEP)
|
Inclusion path of libraries and drivers is implicitly added by Tataouine through the APPS_CFLAGS variable.
As a consequence, including a library or a driver in the C code can be done by using the following syntax:
#include <api/headername.h>
The application layout is automatically generated.
It is important to respect the following variable names, as they are used by the SDK and overloaded as input variables for advanced mechanisms such as multi-bank support:
- APP_NAME
- EXTRA_LDFLAGS
Some variables are set by the SDK (through the included m_config.mk file):
- BUILD_DIR : the build directory of the project
- AFLAGS : the architecture-specific compilation flags
- APPS_CFLAGS : libs and drivers inclusion flags and other arch-specific and warning flags
- PROJ_FILES : the project root directory path
Caution
Please do not set these variables using :=, use instead ?= for paths and += for flags to support overloading, as shown in the sample Makefile
9.11.3.2. The application Kconfig¶
Like all applications, yours must be configured. A typical example is the permissions configuration, but also the required memory or stack. All these information can be set using a Kconfig file (same syntax as the Linux kernel) which allows the usage of ncurses or GTK-based configuration.
Like for Makefiles, applications Kconfig are nearly the same. Only the application name varies.
Hint
You can use the application Kconfig file to add other application-specific configuration elements if needed
80% of the Kconfig file is dedicated to the permissions.
Here is a sample Kconfig file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | # starting PIN application configuration
menu "PIN custom app"
config APP_PIN
bool "Pin App"
depends on STM32F4
default y
---help---
Say y if you want to embbed USER custom application.
# start of (de)actication PIN option list
# all the config entry here depends on the activation of the application
if APP_PIN
config APP_PIN_FW
bool "Pin App for firmware mode"
depends on STM32F4
default y
---help---
Say y if you want to embbed Pin custom application in firmware.
config APP_PIN_DFU
bool "Pin App for DFU mode"
depends on FIRMWARE_DFU
depends on STM32F4
default y
---help---
Say y if you want to embbed Pin custom application in DFU.
config APP_PIN_NUMSLOTS
int "Number of required slots"
default 1
---help---
specify the number of slots required by the application text and data/bss.
remember that the number of total slots is limited by the hardware.
For example, there is 8 32kb sized slots in STM32F4, reduced to 7 when using SHM for
.text + .data in flash, and 8 (reduced to 7 with SHM) slots of 16kb in RAM.
This choice has an impact on the total number of applications that can be loaded
in the firmware.
config APP_PIN_STACKSIZE
int "Stack size"
default 8192
---help---
Specify the application stack size, in bytes. By default, set to 8192
(i.e. 8k). Depending on the number of slots required, and the usage,
the stack can be bigger or smaller.
# start of PIN permission configuration
menu "Permissions"
menu "Devices"
config APP_PIN_PERM_DEV_DMA
bool "App has capacity to register DMA streams"
default n
---help---
if no, the application can't declare a DMA. If y, the application
is able to require one or more secure DMA stream(s).
config APP_PIN_PERM_DEV_CRYPTO
int "App can interact with HW cryptographic module"
default 0
range 0 3
---help---
If 0, the application has no access to any HW cryp module.
If 1, the application is able to use a HW cryp module configured
by another application.
If 2, the application is able to configure (inject keys) but can't
use the crypt module (no IRQ handler).
If 3, the application as a full, autonomous access to the HW cryp
module
config APP_PIN_PERM_DEV_BUSES
bool "App has capacity to use buses (SPI, I2C, USART...)"
default n
---help---
If n, the application can't access any buses (I2C, SPI, USART).
If y, the application can require a bus mapping.
config APP_PIN_PERM_DEV_EXTI
bool "App can use EXTI or GPIO driven external interrupts"
default n
config APP_PIN_PERM_DEV_TIM
bool "App can register a hardware timer"
default n
---help---
If n, the application can't require a timer from the kernel (using
the timer API). If y, the application can require one or more HW
timer(s).
endmenu
menu "Time"
config APP_PIN_PERM_TIM_GETCYCLES
int "App has capacity to get current timestamp from kernel"
default 0
range 0 3
---help---
If 0, the application has no access to timestamping.
If 1, the application is able to get tick accurate timestamping.
If 2, the application is able to get microsecond accurate timestamping.
If 3, the application is able to get cycle accurate timestamping.
endmenu
menu "Tasking"
config APP_PIN_PERM_TSK_FISR
bool "App is allowed to request main thread execution after ISR"
default n
---help---
If y, the application is able to request its main thread execution
just after specific ISRs. This is done using the dev_irq_mode_t
structure in device_t struct, using the IRQ_ISR_FORCE_MAINTHREAD value.
If n, this field can't be set to this value.
config APP_PIN_PERM_TSK_FIPC
bool "App is allowed to request peer execution on syncrhnous send IPC"
default n
---help---
If y, the application is able to request peer thread execution
when sending syncrhonous IPC.
config APP_PIN_PERM_TSK_RESET
bool "App is allowed to request a board software reset"
default n
---help---
If y, the application is able to request a MCU reset. This is usefull
only if the application is handling events that require urgent reactivity
implying board reset.
config APP_PIN_PERM_TSK_UPGRADE
bool "App is allowed to upgrade the firmware"
default n
---help---
If y, the application is able to map the embedded flash device in
order to upgrade the overall firmware. This permission should
be hosted by a task with no external access (USB, USART...)
endmenu
menu "Memory management"
config APP_PIN_PERM_MEM_DYNAMIC_MAP
bool "App is allow to declare MAP_VOLUNTARY devices"
default n
---help---
If y, the task is allowed to declare devices that are not automatically
mapped, but that are mapped/unmapped voluntary using sys_cfg() syscalls.
This permission does not give access to any devices not already declared
but allow dynamic (un)mapping of previously declared ones.
endmenu
endmenu
# end of PIN permission configuration
# Here we can add one (or more) menu, submenu and so on, which
# are specific to the application behavior.
# The menu structure is free, but the option prefix should respect
# the global application prefix (here APP_PIN) to avoid any collision
# or confusion with other part of the configuration
#
# start of PIN specific option configuration
menu "Application specific options"
choice
prompt "PIN human interaction mode"
default APP_PIN_INPUT_USART
config APP_PIN_INPUT_USART
bool "PIN is asked through USART"
---help---
User interaction for PIN ask is done using dedicated
USART interface
config APP_PIN_INPUT_SCREEN
bool "PIN is asked through graphical interface"
---help---
User interaction for PIN ask is done using dedicated
screen/touchscreen couple
endchoice
if APP_PIN_INPUT_USART
config APP_PIN_INPUT_USART_ID
int "PIN USART interface identifier"
range 1 6
endif
endmenu
# end of PIN specific option configuration
# end of (de)actication PIN option list
endif
endmenu
# end of PIN application configuration
|
9.11.4. Integrating your application to the Tataouine SDK¶
This is done by updating the manifest file to add your application repository. The SDK automatically detects that your application is added to the apps/ subdirectory and integrates it to the configuration subsystem.
Now, you only have to activate it using menuconfig, in the same way you configure the Linux kernel, by executing:
make menuconfig
Go to Userspace drivers and features, Applications. You should see your application and should be able to activate it. Until your configuration is saved, you can now directly compile and flash the new version of the firmware with your application integrated in it.
Warning
- Please beware of the following limitations when adding new applications:
- The number of available slots for applications is limited. Too much applications will induce a compilation error
- The user is responsible of the memory ressource management of new applications (stack usage and so on). Some configuration errors here (for instance a stack too small for the app memory needs) will not be caught at compile time, and will lead to crashes (due to memory errors caught by the MPU) that can be hard to debug
- Mistakes and inconsistencies when setting the applications permissions could lead to runtime hazardous errors!
- The user must check the consistency of device drivers usage when adding new applications. For instance, if two applications both try to use USART4 concurrently, one of it will have its request refused by the kernel. As a general rule of thumb, sharing the same piece of hardware in two or more applications (i.e. registers handling the same peripheral) is not permitted and must be resolved by using a userspace proxy