Пример показывает, как встроить виртуальную файловую систему (далее VFS), поставляемую в составе KasperskyOS Community Edition, в разрабатываемую сущность.
В этом примере сущность Client
полностью инкапсулирует реализацию VFS из KasperskyOS Community Edition. Это позволяет избавиться от использования IPC для всех стандартных функций ввода-вывода (stdio.h
, socket.h
и так далее), например, для отладки или повышения производительности.
Сущность Client
тестирует следующие операции:
Поставляемые ресурсы
В пример входит образ жесткого диска с файловой системой FAT32 – hdd.img
.
Этот пример не содержит реализации драйверов блочных устройств, с которыми работает Client
. Эти драйверы (сущности ATA
и SDCard
) поставляются в составе KasperskyOS Community Edition и добавляются в файле сборки ./CMakeLists.txt
.
EDL-описания сущностей
Client.edl
entity client.Client
Реализация сущности Client
main.c
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mount.h>
#define TEST_MESSAGE "test_message"
#define TEST_MESSAGE_LEN 12
int main(void)
{
char buffer[TEST_MESSAGE_LEN + 1];
int ret;
int fd;
memset(buffer, 0, TEST_MESSAGE_LEN);
if (mkdir("/c", S_IRWXU | S_IRWXG | S_IRWXO)) {
printf("Failed to create \"/c\" dir (error %d: \"%s\")\n",
errno,
strerror(errno));
return EXIT_FAILURE;
}
#ifdef __arm__
if (mount("mmc0,0", "/c", "fat32", 0, "")) {
printf("Failed to mount sdcard,0,0, /c, fat32 (error %d: \"%s\")\n",
errno,
strerror(errno));
return EXIT_FAILURE;
}
#else
if (mount("Ahci0Port0,0", "/c", "fat32", 0, "")) {
printf("Failed to mount Ahci0Port0,0, /c, fat32 (error %d: \"%s\")\n",
errno,
strerror(errno));
return EXIT_FAILURE;
}
#endif
fd = open("/c/new_file", O_RDWR | O_CREAT);
if (fd == -1) {
printf("Failed to create new file /c/new_file (error %d: \"%s\")\n",
errno,
strerror(errno));
return -1;
}
ret = write(fd, TEST_MESSAGE, TEST_MESSAGE_LEN);
if (ret != TEST_MESSAGE_LEN) {
printf("Failed to write message to /c/new_file. write() returned %d\n",
ret);
return -1;
}
if (close(fd)) {
printf("Failed to close /c/new_file (error %d: \"%s\")\n",
errno,
strerror(errno));
return -1;
}
fd = open("/c/new_file", O_RDONLY);
if (fd == -1) {
printf("Failed to open existing file /c/new_file (error %d: \"%s\")\n",
errno,
strerror(errno));
return -1;
}
ret = read(fd, buffer, TEST_MESSAGE_LEN);
if (ret != TEST_MESSAGE_LEN) {
printf("Failed to read message from /c/new_file. read() returned %d\n",
ret);
return -1;
}
buffer[TEST_MESSAGE_LEN] = '\0';
printf("Read message: %s\n", buffer);
if (close(fd)) {
printf("Failed to finally close /c/new_file (error %d: \"%s\")\n",
errno,
strerror(errno));
return -1;
}
if (unlink("/c/new_file")) {
printf("Failed to finally unlink /c/new_file (error %d: \"%s\")\n",
errno,
strerror(errno));
return -1;
}
if (umount("/c")) {
printf("Failed to umount /c. error %d: \"%s\"\n",
errno,
strerror(errno));
return EXIT_FAILURE;
}
printf("All devices successfully unmounted\n");
return EXIT_SUCCESS;
}
Init-описание
Сущность Client
работает с блочным устройством напрямую.
init.yaml.in
entities:
- name: client.Client
@INIT_Client_ENTITY_CONNECTIONS@
@INIT_EXTERNAL_ENTITIES@
Конфигурация безопасности
Конфигурация безопасности в этом примере разрешает запуск всех сущностей и позволяет любой сущности обращаться к сущности kl.core.Core
и к драйверу блочного устройства.
security.psl
use common._
use EDL kl.drivers.PCIE
use EDL kl.drivers.ATA
security_arm.psl
use common._
use EDL kl.drivers.SDCard
use EDL kl.drivers.BSP
common.psl
/* Конфигурация безопасности для примера "embedded_vfs". */
/* Определение execute-интерфейса. */
execute: kl.core.Execute
/* Импорт файла с объявлением псевдонимов базовых политик безопасности. */
use nk.base._
/* Объявление сущностей. */
use EDL kl.VfsEntity
use EDL Einit
use EDL kl.core.Core
use EDL client.Client
/* Запуск сущностей разрешен. */
execute {
grant ()
}
/* Сообщения типа request разрешены */
request {
grant ()
}
/* Сообщения типа response разрешены */
response {
grant ()
}
/* Вызовы к security interface игнорируются. */
security {
grant ()
}
Конфигурация сборки
В этом примере используется система автоматизации сборки CMake.
Для обработки EDL-описания сущности Client
используется nk_build_edl_files
, которую предоставляет NK.
Инструкции сборки сущности Client
./client/CMakeLists.txt
project (client)
# Инструментарий для работы с парсером NK.
include (platform/nk)
# Установка флагов компиляции.
project_header_default ("STANDARD_GNU_11:YES" "STRICT_WARNINGS:NO")
nk_build_edl_files (client_edl_files NK_MODULE "client" EDL "${CMAKE_SOURCE_DIR}/resources/edl/Client.edl")
add_executable (Client "src/main.c")
add_dependencies (Client client_edl_files)
# vfs_LOCAL_LIB - необходимо для поддержки встроенной файловой системы.
# vfs_IMPLEMENTATION_LIB - реализация файловой системы.
target_link_libraries (Client ${vfs_LOCAL_LIB} ${vfs_IMPLEMENTATION_LIB} ${VFAT_LIB})
#set_target_properties (Client PROPERTIES LINK_FLAGS "-Ttext 0x00800000")
Инструкции сборки сущности Einit и образа системы
./einit/CMakeLists.txt
project (einit)
# Инструментарий для работы с парсером NK.
include (platform/image)
# Установка флагов компиляции.
project_header_default ("STANDARD_GNU_11:YES" "STRICT_WARNINGS:NO")
if ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm|aarch64")
# Подключение пакета, импортирующего компоненты для работы с SD-картой.
find_package (sdcard REQUIRED)
include_directories (${sdcard_INCLUDE})
# We need SDCARD driver to be connected with our implementation of VFS
set_target_properties (Client PROPERTIES ${blkdev_ENTITY}_REPLACEMENT ${sdcard_ENTITY})
# Добавляем цель с копированием образа диска в директорию сборки примера.
add_custom_target (hdd.img
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/hdd
COMMAND ${CMAKE_COMMAND} -E copy_directory
${KL_SDK_ROOT_PATH}/common/hdd ${CMAKE_BINARY_DIR}/hdd
COMMAND ${KL_SDK_ROOT_PATH}/common/prepare_hdd_img.sh -d ${CMAKE_BINARY_DIR}/hdd -img hdd.img -f fat32 -s 128)
# Для архитектуры Arm поддерживается работа только с одной SD-картой.
set (QEMU_FLAGS "-nographic -monitor none -sd hdd.img")
else ()
# Подключение пакета, импортирующего компоненты для работы с ata-устройством.
find_package (ata REQUIRED)
include_directories (${ata_INCLUDE})
# We need ATA driver to be connected with our implementation of VFS
set_target_properties (Client PROPERTIES ${blkdev_ENTITY}_REPLACEMENT ${ata_ENTITY})
# Добавляем цели с копированием образов дисков в директорию сборки примера.
add_custom_target (hdd.img
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/hdd
COMMAND ${CMAKE_COMMAND} -E copy_directory
${KL_SDK_ROOT_PATH}/common/hdd ${CMAKE_BINARY_DIR}/hdd
COMMAND ${KL_SDK_ROOT_PATH}/common/prepare_hdd_img.sh -d ${CMAKE_BINARY_DIR}/hdd -img hdd.img -f fat32 -s 128)
set (QEMU_FLAGS "-nographic -monitor none \
-device ahci,id=ahci \
-drive id=disk,file=hdd.img,if=none \
-device ide-drive,drive=disk,bus=ahci.0")
endif ()
if ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "arm")
set (SECURITY_PSL_FILE "src/security.arm.psl")
else ()
set (SECURITY_PSL_FILE "src/security.psl")
endif ()
set (QEMU_DEPENDENCIES hdd.img)
# Образ KasperskyOS для аппаратной платформы.
build_kos_hw_image (kos-image
EINIT_ENTITY EinitHw
CONNECTIONS_CFG "src/init.yaml.in"
SECURITY_PSL ${SECURITY_PSL_FILE}
IMAGE_FILES Client)
# Образ KasperskyOS для QEMU с целями эмуляции (sim, gdbsim, gdb).
build_kos_qemu_image (kos-qemu-image
EINIT_ENTITY EinitQemu
CONNECTIONS_CFG "src/init.yaml.in"
SECURITY_PSL ${SECURITY_PSL_FILE}
QEMU_FLAGS "${QEMU_FLAGS}"
QEMU_DEPENDENCIES "${QEMU_DEPENDENCIES}"
IMAGE_FILES Client)
#set_target_properties (EinitQemu PROPERTIES LINK_FLAGS "-Ttext 0x00200000")
Инструкции сборки решения
./CMakeLists.txt
cmake_minimum_required (VERSION 3.12)
# Инициализация библиотеки CMake
include (platform)
initialize_platform ()
# Подключение функций установки артефактов.
include (platform/install)
# Добавление документации в формате Doxygen
include (platform/doxygen)
add_project_documentation_main_target ()
# Подключение пакета, импортирующего компоненты для работы с
# виртуальной файловой системой.
find_package (vfs REQUIRED)
include_directories (${vfs_INCLUDE})
# Подключение пакета, импортирующего компоненты для работы с
# VFAT
find_package (VFAT REQUIRED)
include_directories (${VFAT_INCLUDE})
add_subdirectory (client)
add_subdirectory (einit)
Сборка с помощью CMake
Для сборки и запуска примера необходимо выполнить следующий скрипт:
/opt/KasperskyOS-Community-Edition-<version>/examples/embedded_vfs/cross-build.sh