shared memory utils

This commit is contained in:
Andrey Romanina 2024-07-01 12:29:22 +03:00
parent 998279b54d
commit 682711c2a6
13 changed files with 473 additions and 0 deletions

54
utils/FileToSharedMem/.vscode/launch.json vendored Executable file
View File

@ -0,0 +1,54 @@
{
"configurations": [
{
"name": "(gdb) DevMem am64xx_Debug",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/out/build/am64xx_Debug/DevMem",
"MIMode": "gdb",
"cwd": "${workspaceFolder}",
"stopAtEntry": true,
"miDebuggerPath": "/usr/bin/gdb-multiarch",
"miDebuggerServerAddress": "192.168.0.5:5000",
"miDebuggerArgs": "",
"setupCommands": [
{
"description": "Включить автоматическое форматирование для gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Задать для варианта приложения дизассемблирования значение Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
},
{
"name": "(gdb) FileToSharedMem am64xx_Debug",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/out/build/am64xx_Debug/FileToSharedMem",
"MIMode": "gdb",
"cwd": "${workspaceFolder}",
"stopAtEntry": true,
"miDebuggerPath": "/usr/bin/gdb-multiarch",
"miDebuggerServerAddress": "192.168.0.5:5000",
"miDebuggerArgs": "",
"setupCommands": [
{
"description": "Включить автоматическое форматирование для gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Задать для варианта приложения дизассемблирования значение Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
}
],
"version": "2.0.0"
}

View File

@ -0,0 +1,7 @@
{
"files.associations": {
"*.tcc": "cpp",
"stdexcept": "cpp",
"ostream": "cpp"
}
}

View File

@ -0,0 +1,51 @@
cmake_minimum_required(VERSION 3.17)
project(FileToSharedMem)
# Подключаем исходные файлы проекта.
set(SOURCES
MemMapping.cpp MemMapping.h
)
# Подключаем внешние зависимости.
include(FetchContent)
include(SharedLibraries.cmake)
# Определяем зависимости, являющиеся общими для всех целей.
set(LIST_OF_SHARED_LIBRARIES
cxxopts
)
# Определяем свойства, являющиеся общими для всех целей.
set(LIST_OF_SHARED_PROPERTIES
CXX_STANDARD 20
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
)
add_executable(FileToSharedMem FileToSharedMem.cpp ${SOURCES})
add_executable(DevMem DevMem.cpp ${SOURCES})
# Добавляем корневую директорию для того чтобы избежать инклюдов с ../
target_include_directories(FileToSharedMem PRIVATE ${PROJECT_SOURCE_DIR})
target_include_directories(DevMem PRIVATE ${PROJECT_SOURCE_DIR})
# Подключаем зависимости.
target_link_libraries(FileToSharedMem PRIVATE ${LIST_OF_SHARED_LIBRARIES})
target_link_libraries(DevMem PRIVATE ${LIST_OF_SHARED_LIBRARIES})
# Определяем свойства.
set_target_properties(FileToSharedMem PROPERTIES ${LIST_OF_SHARED_PROPERTIES})
set_target_properties(DevMem PROPERTIES ${LIST_OF_SHARED_PROPERTIES})
# Подключаем зависимости платформы.
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(WIN_SHARED_LIBRARIES -Wl,-Bstatic,--whole-archive -static-libgcc -static-libstdc++ -lwinpthread
-Wl,--no-whole-archive wsock32 ws2_32
)
target_link_libraries(FileToSharedMem PRIVATE ${WIN_SHARED_LIBRARIES})
target_link_libraries(DevMem PRIVATE ${WIN_SHARED_LIBRARIES})
endif()

View File

@ -0,0 +1,78 @@
{
"version": 3,
"configurePresets": [
{
"name": "default",
"displayName": "default",
"description": "Default build using Ninja generator",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"cacheVariables": {
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}"
}
},
{
"name": "x86_64_Debug",
"inherits": "default",
"displayName": "x86_64 Debug",
"description": "Degub build for x86_64",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_C_COMPILER": "gcc",
"CMAKE_CXX_COMPILER": "g++"
}
},
{
"name": "x86_64_Release",
"inherits": "x86_64_Debug",
"displayName": "x86_64 Release",
"description": "Release build for x86_64",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "am64xx_Debug",
"inherits": "default",
"displayName": "am64xx Debug",
"description": "Degub build for am64xx-evm board(arm cortex-a53)",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_TOOLCHAIN_FILE": "${workspaceFolder}/../../compile/toolchain.cmake",
"BOARD": "am64xx-evm"
},
"environment": {
"ENV_TARGET_CROSS_COMPILE_PREFIX": "/opt/ti-processor-sdk-linux-am64xx-evm-09.02.00.08/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/aarch64-oe-linux/aarch64-oe-linux-",
"ENV_TARGET_SYSTOOT_PATH": "/opt/ti-processor-sdk-linux-am64xx-evm-09.02.00.08/linux-devkit/sysroots/aarch64-oe-linux"
}
},
{
"name": "am64xx_Release",
"inherits": "am64xx_Debug",
"displayName": "am64xx Release",
"description": "Release build for am64xx-evm board(arm cortex-a53)",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
],
"buildPresets": [
{
"name": "x86_64 Debug",
"configurePreset": "x86_64_Debug"
},
{
"name": "x86_64 Release",
"configurePreset": "x86_64_Release"
},
{
"name": "am64xx Release",
"configurePreset": "am64xx_Release"
},
{
"name": "am64xx Debug",
"configurePreset": "am64xx_Debug"
}
]
}

View File

@ -0,0 +1,42 @@
#include <iostream>
#include <cstring>
#include "MemMapping.h"
int main(int argc, char **argv)
{
switch(argc)
{
case 2:
{
size_t addrPhys = std::stoull(argv[1], nullptr, 0);
int val;
MemMapping map(O_RDONLY, addrPhys, sizeof(val), PROT_READ, MAP_PRIVATE);
memcpy(&val, map.get(), sizeof(val));
std::cout << "0x" << std::hex << val << std::endl;
}
break;
case 3:
{
size_t addrPhys = std::stoull(argv[1], nullptr, 0);
int val = std::stoull(argv[2], nullptr, 0);
MemMapping map(O_RDWR | O_SYNC, addrPhys, sizeof(val), PROT_READ | PROT_WRITE, MAP_SHARED);
memcpy(map.get(), &val, sizeof(val));
}
break;
default:
{
std::cout << "Wrong argument count!" << std::endl;
std::cout << "Usage:" << std::endl;
std::cout << "Read 32 bits: devmem 0x12345678" << std::endl;
std::cout << "Write 32 bits: devmem 0x12345678 314159" << std::endl;
}
break;
}
return 0;
}

View File

@ -0,0 +1,103 @@
#include <iostream>
#include <cxxopts.hpp>
#include <filesystem>
#include <fstream>
#include <stdexcept>
#include <cstdint>
#include "MemMapping.h"
int main(int argc, char * argv[]) {
using namespace std::literals::string_literals;
using namespace std::literals::string_view_literals;
cxxopts::Options options(
"FileToSharedMem",
"FileToSharedMem: copies file content to memory location.\n"
""
);
options.set_width(160);
options.add_options()
("help", "Display this help", cxxopts::value<bool>()->default_value("false"))
("verbose", "Verbose output", cxxopts::value<bool>()->default_value("true"))
("file", "Set binary file path", cxxopts::value<std::string>()->default_value("Project.bin"))
("addr", "Set memory physical address", cxxopts::value<std::string>()->default_value("0xa6000000"));
auto result = options.parse(argc, argv);
if (result["help"].as<bool>())
return not( std::cout << options.help() << std::endl );
std::string file_path = result["file"].as<std::string>();
uint64_t addr = std::stoull(result["addr"].as<std::string>(), nullptr, 0);
std::ifstream fin(file_path, std::ios::in | std::ios::binary);
if(!fin)
{
fprintf(stderr, "Couldn't open file %s", file_path);
exit(1);
}
//service fields in shared mem
struct
{
uint32_t len;
uint32_t mark;
} service = {.len = std::filesystem::file_size(file_path), .mark = 0};
const int accessQuant = 8;
const int map_len = service.len + sizeof(service) + accessQuant; //с небольшим запасом
MemMapping map(O_RDWR | O_SYNC, addr, map_len, PROT_READ | PROT_WRITE, MAP_SHARED);
void * pDst = map.get();
memcpy(pDst, &service, sizeof(service));
pDst += sizeof(service);
{
const uint32_t mask = accessQuant - 1;
const int buf_len = (service.len & mask) ? ((service.len & ~mask) + accessQuant) : service.len;
std::vector<char> buf(buf_len);
if(!fin.read(buf.data(), service.len))
{
fprintf(stderr, "Couldn't read from file");
exit(1);
}
memcpy(pDst, buf.data(), buf.size());
// По одному байту работает, но некрасиво
//
// int i;
// char * p = (char *)pDst;
// const char * pSrc = buf.data();
// for(i = 0; i < service.len; i++)
// *p++ = *pSrc++;
}
//Так нельзя - получаем Bus error
//
// if(!fin.read((char *)pDst, service.len))
// {
// fprintf(stderr, "Couldn't read from file");
// exit(1);
// }
service.mark = 0x12345678;
pDst = map.get();
memcpy(pDst, &service, sizeof(service));
return 0;
}

View File

@ -0,0 +1,49 @@
#include "MemMapping.h"
#include <iostream>
#include <stdexcept>
#include <unistd.h>
MemMapping::MemMapping(int memOpenFlags, size_t addr, size_t size, int mmapProt, int mmapFlags)
{
const size_t pageMask = sysconf(_SC_PAGESIZE) - 1;
const size_t pageAddr = addr & ~(pageMask); //базовый адрес страницы
m_pageOffset = addr & pageMask; //смещение относительно начала страницы
int fd = open("/dev/mem", memOpenFlags);
if(fd < 0)
{
fprintf(stderr, "Can't open /dev/mem, flags=0x%X, %s line %i\n", memOpenFlags, __FILE__, __LINE__);
throw std::runtime_error("MemMapping failed");
}
// mmap() делается с адреса, кратного странице -> выделяемый размер нужно увеличить на величину смещения внутри страницы
m_size = size + m_pageOffset;
m_mapAddr = mmap(NULL,
m_size,
mmapProt,
mmapFlags,
fd,
pageAddr);
//После mmap регистров дескриптор больше не нужен - закрываем файл
close(fd);
if(m_mapAddr == MAP_FAILED)
{
fprintf(stderr, "MemMapping: can't mmap addr=0x%X size=0x%X errno=%i\n", addr, size, errno);
throw std::runtime_error("MemMapping failed");
}
}
MemMapping::~MemMapping()
{
if(munmap(m_mapAddr, m_size) < 0)
{
fprintf(stderr, "MemMapping: can't unmap addr=0x%X size=0x%X errno=%i\n", m_mapAddr, m_size, errno);
}
}

View File

@ -0,0 +1,25 @@
#pragma once
#include <stdint.h>
#include <fcntl.h>
#include <sys/mman.h>
class MemMapping
{
public:
/*
* memOpenFlags - параметры доступа к /dev/mem, например O_RDWR, O_SYNC
* addr - физический адрес в памяти, м.б. не кратен размеру страницы
* mmapProt - параметры mmap, например PROT_READ | PROT_WRITE
* mmapFlags - параметры mmap, например MAP_SHARED
*/
MemMapping(int memOpenFlags, size_t addr, size_t size, int mmapProt, int mmapFlags);
~MemMapping();
void * get() { return m_mapAddr + m_pageOffset; };
private:
void * m_mapAddr; //замапированный виртуальный адрес, кратный размеру страницы
size_t m_size; //замапированный размер
size_t m_pageOffset; //отступ исходного addr от начала страницы
};

View File

@ -0,0 +1,9 @@
# Specify the path to dependencies' git repositories
cmake_path(SET cxxopts_path "git@sofdev:External/cxxopts.git")
if (
NOT DEFINED cxxopts_path)
message(FATAL_ERROR "Path to the dependency git repository is not specified")
endif()

View File

@ -0,0 +1,13 @@
include(RepositoryPath.cmake)
FetchContent_Declare(
cxxopts
GIT_REPOSITORY ${cxxopts_path}
GIT_TAG master
)
FetchContent_GetProperties(cxxopts)
if(NOT cxxopts_POPULATED)
FetchContent_Populate(cxxopts)
add_subdirectory(${cxxopts_SOURCE_DIR} ${cxxopts_BINARY_DIR})
endif()

View File

@ -0,0 +1,16 @@
# $1 - root@192.168.0.5
# $2 - ../out/build/am64xx_Debug/PeaceTrueNetConnector
$(dirname "$0")/copy_app $1 $2
ssh $1 <<END_SCRIPT
cd /home/root/
chmod 777 $(basename "$2")
gdbserver :5000 $(basename "$2")
exit
END_SCRIPT

View File

@ -0,0 +1,12 @@
# $1 - root@192.168.0.5
# $2 - ../out/build/am64xx_Debug/PeaceTrueNetConnector
ssh $1 <<END_SCRIPT
killall gdbserver
exit
END_SCRIPT
scp $2 $1:/home/root/

View File

@ -0,0 +1,14 @@
# $1 - root@192.168.0.5
# $2 - ../out/build/am64xx_Debug/PeaceTrueNetConnector
ssh $1 <<END_SCRIPT
cd /home/root/
chmod 777 $(basename "$2")
gdbserver :5000 $(basename "$2")
exit
END_SCRIPT