Пример собственной реализации виртуальной файловой системы (далее VFS).
Для вывода в stdout
используется пример реализации VFS – сущность CustomVfs
.
EDL-описания сущностей
Client.edl
entity client.Client
CustomVfs.edl
entity custom_vfs.CustomVfs
components {
vfs: kl.Vfs
}
Init-описание
Для использования потока stdout
сущность Client
должна иметь доступ к сущности VFS (CustomVfs
).
Этот пример содержит два файла init-описаний:
init_qemu.yaml.in
для запуска на эмуляторе QEMU;init_hw.yaml.in
для запуска на устройствах.init_qemu.yaml.in
entities:
- name: client.Client
path: client
connections:
- target: custom_vfs.CustomVfs
id: {var: _VFS_CONNECTION_ID, include: vfs/defs.h}
@INIT_client_ENTITY_CONNECTIONS+@
- name: custom_vfs.CustomVfs
path: custom_vfs_hw
@INIT_custom_vfs_hw_ENTITY_CONNECTIONS@
@INIT_EXTERNAL_ENTITIES@
init_hw.yaml.in
entities:
- name: client.Client
path: client
connections:
- target: custom_vfs.CustomVfs
id: {var: _VFS_CONNECTION_ID, include: vfs/defs.h}
@INIT_client_ENTITY_CONNECTIONS+@
- name: custom_vfs.CustomVfs
path: custom_vfs_qemu
@INIT_custom_vfs_qemu_ENTITY_CONNECTIONS@
@INIT_EXTERNAL_ENTITIES@
Конфигурация безопасности
Конфигурация безопасности в этом примере разрешает запуск всех сущностей и позволяет любой сущности обращаться к сущностям Core
и CustomVfs
.
security.psl
/* Конфигурация безопасности для примера "custom_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
use EDL custom_vfs.CustomVfs
/* Запуск сущностей разрешен. */
execute {
grant ()
}
/* Сообщения типа request разрешены. */
request {
grant ()
}
/* Сообщения типа response разрешены. */
response {
grant ()
}
/* Вызовы к security interface игнорируются. */
security {
grant ()
}
Реализация сущности Client
Сущность Client
выводит в stdout
фразу "Hello, world!"
.
client.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
printf("Hello, World!\n");
return EXIT_SUCCESS;
}
Реализация сущности CustomVfs
Сущность CustomVfs
предоставляет собственную реализацию метода write
из интерфейса IFilesystem
.
custom_vfs.c
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#define _VFS_SERVER_INTERFACE
#include <vfs/basic.h>
#include <uart/uart.h>
/* Первый порт UART. */
static UartHandle uartH = 0;
/* Подготовить vfs к выводу в UART. */
static int uart_init(UartHandle *uartH)
{
/* Инициализировать драйвер UART. */
int rc = UartInit();
if (rc != UART_OK)
return -1;
/* Открыть порт. */
rc = UartOpenPort(PORT_NAME, uartH);
if (rc != UART_OK)
return -1;
return 0;
}
/* Обязательные действия для подготовки виртуальной файловой системы. */
/* Реализация инициализирующей функции. */
bool _vfs_implementation_init(Handle self_id, int *error)
{
(void)self_id;
(void)error;
/* Возвращает FALSE, если инициализация UART прошла неуспешно. */
if (uart_init(&uartH) == -1)
return false;
/* Возвращает TRUE. */
return true;
}
/* Реализация завершающей функции. */
void _vfs_implementation_free(void)
{
/* Не выполняет никаких действий. */
}
/* Реализация метода "write" из интерфейса IFilesystem. */
ssize_t _vfs_write(Handle client_id, Handle fd, const void *buf, size_t count, int *error)
{
/* Работаем только потоками stdout и stderr, т.к. в примере отсутствует файловая система. */
if (fd == 1 || fd == 2)
{
static const char msg[] = "Custom vfs uses UART to print this message...\n";
int i;
/* Вывести сообщение в порт UART. */
for (i = 0; i < sizeof(msg) - 1; ++i)
UartWriteByte(uartH, (uint8_t)msg[i]);
/* Вывести переданную строку в порт UART. */
for (i = 0; i < count; ++i)
UartWriteByte(uartH, (uint8_t)(*((const char *)buf + i)));
/* Ошибки нет. */
*error = 0;
/* Возвращаем размер буфера, который был записан. */
return count;
}
/* Для иных файловых дескрипторов возвращаем ошибку. */
*error = EROFS;
return -1;
}
/* Выполнять диспетчеризацию в основном потоке. */
#define WE_DONT_NEED_THE_MAIN_THREAD 1
#if WE_DONT_NEED_THE_MAIN_THREAD
static _vfs_server_thread_routine_t thread_routine;
static void *thread_routine_arg;
/* Определение этой функции необходимо для выполнения диспетчеризации методов интерфейса IFilesystem
в основном потоке. */
void _vfs_server_set_main_thread_routine(_vfs_server_thread_routine_t func, void *arg)
{
thread_routine = func;
thread_routine_arg = arg;
}
int main(void)
{
assert(thread_routine != NULL);
/* Запуск диспетчеризации. */
(*thread_routine)(thread_routine_arg);
return EXIT_SUCCESS;
}
#else
/* Диспетчеризация выполняется в отдельном потоке, т.к. функция _vfs_server_set_main_thread_routine
не определена. */
int main(void)
{
while (1) continue;
return EXIT_SUCCESS;
}
#endif
Инструкции сборки решения
В этом примере используется система автоматизации сборки 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/client.c")
target_link_libraries (client ${vfs_CLIENT_LIB})
#set_target_properties (client PROPERTIES LINK_FLAGS "-Ttext 0x00800000")
# We do not need default VFS entity here, which comes from ${vfs_CLIENT_LIB}
set_target_properties (client PROPERTIES ${vfs_ENTITY}_REPLACEMENT "")
add_dependencies (client client_edl_files)
Инструкции сборки сущности CustomVfs
./custom_vfs/CMakeLists.txt
project (custom_vfs)
# Инструментарий для работы с парсером NK.
include (platform/nk)
# Установка флагов компиляции.
project_header_default ("STANDARD_GNU_11:YES" "STRICT_WARNINGS:NO")
nk_build_edl_files (custom_vfs_edl_files NK_MODULE "custom_vfs" EDL "${CMAKE_SOURCE_DIR}/resources/edl/CustomVfs.edl")
if (uart_HW_LIB)
add_executable (custom_vfs_hw "src/custom_vfs.c")
target_compile_definitions (custom_vfs_hw PRIVATE "-DPORT_NAME=\"${PORT_HW}\"")
target_link_libraries (custom_vfs_hw ${vfs_SERVER_LIB} ${uart_HW_LIB})
add_dependencies (custom_vfs_hw custom_vfs_edl_files)
endif ()
add_executable (custom_vfs_qemu "src/custom_vfs.c")
target_compile_definitions (custom_vfs_qemu PRIVATE "-DPORT_NAME=\"uart0\"")
target_link_libraries (custom_vfs_qemu ${vfs_SERVER_LIB} ${uart_QEMU_LIB})
#set_target_properties (custom_vfs_qemu PROPERTIES LINK_FLAGS "-Ttext 0x00800000")
add_dependencies (custom_vfs_qemu custom_vfs_edl_files)
Инструкции сборки сущности einit и образа системы
./einit/CMakeLists.txt
project (einit)
# Инструментарий для работы с парсером NK.
include (platform/image)
# Установка флагов компиляции.
project_header_default ("STANDARD_GNU_11:YES" "STRICT_WARNINGS:NO")
# Блочные устройства в этом примере не требуются.
set_target_properties (${vfs_DEFAULT_ENTITY} PROPERTIES
${blkdev_ENTITY}_REPLACEMENT ""
${pcie_ENTITY}_REPLACEMENT "")
# Определение переменной ENTITIES_QEMU со списком сущностей.
set (ENTITIES_QEMU client custom_vfs_qemu)
# Определение переменной ENTITIES_HW со списком сущностей.
if (TARGET custom_vfs_hw)
set (ENTITIES_HW client custom_vfs_hw)
set (CONNECTIONS_CFG_HW "src/init_hw.yaml.in")
else ()
set (ENTITIES_HW ${ENTITIES_QEMU})
set (CONNECTIONS_CFG_HW "src/init_qemu.yaml.in")
endif ()
set (SECURITY_PSL "src/security.psl")
set (QEMU_FLAGS "-nographic -monitor none")
# Образ KasperskyOS для аппаратной платформы.
build_kos_hw_image (kos-image
EINIT_ENTITY EinitHw
CONNECTIONS_CFG "${CONNECTIONS_CFG_HW}"
SECURITY_PSL "${SECURITY_PSL}"
IMAGE_FILES ${ENTITIES_HW})
# Образ KasperskyOS для QEMU с целями эмуляции (sim, gdbsim, gdb).
build_kos_qemu_image (kos-qemu-image
EINIT_ENTITY EinitQemu
CONNECTIONS_CFG "src/init_qemu.yaml.in"
SECURITY_PSL "${SECURITY_PSL}"
QEMU_FLAGS "${QEMU_FLAGS}"
IMAGE_FILES ${ENTITIES_QEMU})
#set_target_properties (EinitQemu PROPERTIES LINK_FLAGS "-Ttext 0x00200000")
Инструкции сборки решения
./CMakeLists.txt
cmake_minimum_required (VERSION 3.12)
# Инициализация библиотеки CMake
include (platform)
initialize_platform ()
# Добавление документации в формате Doxygen
include (platform/doxygen)
add_project_documentation_main_target ()
# Подключение функций установки артефактов.
include (platform/install)
# Эта команда найдет все компоненты пакета uart.
find_package (uart REQUIRED)
include_directories (${uart_INCLUDE})
# Подключение пакета, импортирующего компоненты для работы с
# виртуальной файловой системой.
find_package (vfs REQUIRED)
include_directories (${vfs_INCLUDE})
add_subdirectory (client)
add_subdirectory (custom_vfs)
add_subdirectory (einit)
Сборка с помощью CMake
Для сборки и запуска примера необходимо выполнить следующий скрипт:
/opt/KasperskyOS-Community-Edition-<version>/examples/custom_vfs/cross-build.sh