SlideShare a Scribd company logo
Исключительная
модель памяти
АЛЕКСЕЙ ТКАЧЕНКО
ОАО «ПЕЛЕНГ»
TKACHENKO@PELENG.BY, ALEXEY.TKACHENKO@GMAIL.COM
HTTPS://GITHUB.COM/ALEXEY-TKACHENKO/
Об авторе
Ведущий разработчик ОАО «Пеленг»
Специализируюсь на испытательном оборудовании для
космической аппаратуры
В свободное время делаю pet-проекты, в том числе embedded
Вижу боль embedded-разработчиков и хочу помочь
2
План доклада
Регистровые аппаратные интерфейсы
Имитация аппаратных интерфейсов с помощью механизмов
защиты памяти
Библиотека ExMM для имитации регистрового аппаратного
интерфейс
3
Трансляция адресов памяти
4
Трансляция адресов памяти
5
Модель ввода-вывода
6
Модель ввода-вывода
7
Свойства регистров:
• Назначение битов определяется контроллером
• Биты не обязательно доступны для чтения/записи
(пример – MSR, например EFlags в x86)
• Чтение/запись могут быть асимметричными
• В общем случае не предполагается хранение содержимого
Пример: EFlags @ x86
8
Модель ввода-вывода
9
Регистры: ячейка памяти
10
Регистры: счётчик
11
Регистры: сторожевой таймер
12
Регистры: защёлка
13
Регистры: статусные флаги
14
Исходные данные
•Подходы при взаимодействии периферийных устройств с программным
обеспечением достаточно разнообразны
•Память, основанная на ячейках, хранящих информацию, не годится для
моделирования всего многообразия аппаратных интерфейсов
•Язык реализации многих низкоуровневых драйверов для
микроконтроллеров – Си, который имеет не слишком развитые средства
абстрагирования, а если их реализовывать, поддержка абстрагирования
часто является слишком дорогой из-за роста сложности и снижения
быстродействия критического к производительности кода
•Многие драйверы уже написаны и в них не были заложены возможности
тестирования.
15
Постановка задачи
•Моделирование поведения на уровне исходников. Полное моделирование
поведения всего устройства не предполагается.
•Поддержка возможности встраивания в систему непрерывной интеграции
для выполнения регрессионных тестов
•Работа под операционными системами Windows, Linux, macOS на
архитектурах процессоров x86, x86_64, ARM (в т.ч. Thumb и Thumb2),
ARM64, Aarch64 (при поддержке соответствующих ОС)
•Поддержка одновременной работы множества моделей контроллеров
•Простота реализации моделей контроллеров
16
Что имеем?
Операционные системы могут реагировать на обращение к диапазонам адресов
виртуальной памяти:
Подкачка
Проецирование файлов в память
Совместное использование библиотек
Выделение памяти по требованию
Механизм copy-on-write
Ошибка доступа к памяти
Операционным системам для работы с виртуализацией памяти требуется наличие
аппаратного MMU
Операционные системы транслируют аппаратные исключения доступа к памяти MMU (и не
только их) в исключения или сигналы в контексте спровоцировавшего процесса
Существует возможность перехвата исключений/сигналов в пользовательском процессе
17
Что имеем?
Windows POSIX
Выделение памяти VirtualAlloc mmap
Настройка доступа VirtualProtect mprotect
Перехват Structured Exception Handling Signals
Контекст потока Полный Частичный
18
Перехваты чтения и записи
После записи регистра необходимо вызвать обработчик модели и
выполнить обработку записанного пользовательским кодом в ячейку
памяти значения
При чтении регистра необходимо вызвать обработчик в модели и
предоставить пользовательскому коду значение запрашиваемой ячейки
памяти
19
Порядок действий при перехвате
Перехват записи Перехват чтения
При обращении к защищённой области памяти MMU формирует ошибку доступа, которую операционная
система транслирует в сигнал SIGSEGV или исключение с кодом EXCEPTION_ACCESS_VIOLATION.
Снять защиту с регистрового файла
Вызвать перехватчик чтения модели контроллера
Включить пошаговое выполнение или установить точку останова на следующей инструкции
Снять защиту с регистрового файла
Перезапустить инструкцию, вызвавшую исключение
После завершения инструкции чтения/записи процессор сгенерирует событие трассировки, которое
операционная система транслирует в сигнал SIGTRAP или исключение с кодом EXCEPTION_SINGLE_STEP
Отключить трассировку/точку исключения
Вызвать перехватчик записи модели контроллера
Восстановить исходную защиту памяти и продолжить выполнение программы
20
Другие аспекты
1. При начале работы контроллера может требоваться инициализация
регистрового файла некоторыми начальными значениями
2. Генерация и обработка прерываний
3. Синхронизация доступа к регистровому файлу
4. Фоновая работа модели периферийного устройства может требовать особой
работы с регистровым файлом
5. Необходима поддержка отладки как пользовательского кода (драйвера), так и
модели контроллера
21
Требования к клиентскому коду
1. Регистровый файл должен быть объявлен как volatile-память
2. Пользовательский код не должен полагаться на абсолютные адреса областей
памяти
3. Обработчик прерывания должен быть реализован в отдельной функции,
которая может быть вызвана как из обработчика исключения (часто
оформленного в виде макроса ISR), так и как функция обратного вызова из
библиотечного кода
22
Библиотека ExMM
Библиотека реализует всё, что описано выше
Меньше 2000 строк кода!
Open-source, размещена на Github по адресу:
https://github.com/Alexey-Tkachenko/ExMM/
Скоро в виде Conan-пакета
23
Начало работы
1. Подключить библиотеку:
#include <exmm.hpp>
using namespace ExMM;
2. Определить структуру регистров:
struct Registers
{
volatile int A;
volatile int B;
volatile int C;
};
24
Начало работы
3. Реализовать класс модели контроллера:
struct MyController final : public ControllerBase<HookTypes::ReadWrite, Registers>
{
void HookRead(volatile Registers* data, size_t offset) override
{}
void HookWrite(volatile Registers* data, size_t offset) override
{}
};
25
Начало работы
4. Создать объект контроллера:
MyController controller;
5. Получить указатель на регистровый файл:
volatile Registers *registers = controller.GetIoArea();
6. Запустить код в управляемом блоке:
ExMM::Run([&registers]()
{
registers->A = 42;
registers->B = 123;
registers->C = -1;
});
26
Простой перехватчик
struct MyController final : public ControllerBase<HookTypes::ReadWrite, Registers>
{
void HookRead(volatile Registers* data, size_t offset) override
{
std::cout << "Before read at offset " << std::hex << offset << std::endl;
}
void HookWrite(volatile Registers* data, size_t offset) override
{
std::cout << "After write at offset " << std::hex << offset << std::endl;
}
};
27
Перехватчик, реализующий защёлку
struct Registers
{
volatile uint32_t TimeLo; // Microseconds
volatile uint32_t TimeHi; // Integral seconds
};
class LatchController final : public ControllerBase<HookTypes::Read, Registers>
{
| uint32_t latchedLoValue;
std::chrono::high_resolution_clock::time_point whenStarted;
public:
LatchController()
: whenStarted(std::chrono::high_resolution_clock::now()),
latchedLoValue()
{}
void HookRead(volatile Registers *data, size_t offset) override;
};
28
Перехватчик, реализующий защёлку
void LatchController::HookRead(volatile Registers *data, size_t offset)
{
SwitchField(data, offset)
| .Case(&Registers::TimeLo,
| [this](auto &timeLo) { timeLo = latchedLoValue; })
| .Case(&Registers::TimeHi,
[this](auto &timeHi) {
static const std::chrono::seconds oneSecond{1};
const auto elapsed = std::chrono::high_resolution_clock::now() - whenStarted;
const auto us = std::chrono::duration_cast<std::chrono::microseconds>(elapsed);
const auto seconds = us / oneSecond;
| latchedLoValue = static_cast<uint32_t>((us % oneSecond).count());
| timeHi = static_cast<uint32_t>(seconds);
});
}
29
Поддержка массивов
struct Registers
{
// ...
volatile uint32_t Telemetry[4];
};
void SomeController::HookRead(volatile Registers* data, size_t offset)
{
SwitchField(data, offset)
| .CaseArray(&Registers::Telemetry, [this](std::size_t index, auto& tm)
{
tm = shadowRecord.Words[index];
});
}
30
Вложенные агрегаты
struct Registers
{
struct TimerData
{
uint32_t TriggerTimeHi; // Time when timer triggers, seconds.
uint32_t TriggerTimeLo; // Time when timer triggers, microseconds.
};
| volatile TimerData Timers[8]; // Сonfiguration.
};
void SomeController::HookWrite(volatile Registers *data, size_t offset)
{
SwitchField(data, offset)
| .InsideArray(&Registers::Timers, [](std::size_t index, auto &next) {
| next.Case(&Registers::TimerData::TriggerTimeHi, [](auto &value) { ... })
.Case(&Registers::TimerData::TriggerTimeLo, [](auto &value)
{ value = std::min(uint32_t{value}, 999999u); }
);
});
}
31
Необработанный доступ
void SomeController::HookWrite(Registers *data, size_t offset)
{
SwitchField(data, offset)
.Case(&Registers::ControlWord, [this](auto &value) { ...})
.Case(&Registers::StatusWord, [this](auto &value) { ... })
.InsideArray(&Registers::Timers, [](std::size_t index, auto &next) { ... })
| .Else([data](size_t offset) {
std::cout << "((not observed)) "
<< reinterpret_cast<volatile uint32_t *>(data)[offset / 4]
<< std::endl;
});
}
32
Поддержка платформ
33
Известные проблемы
Необработанный доступ на Linux за пределами памяти контроллера
завершает процесс
Низкая производительность DSL
Неполная документация
34
Дальнейшие планы
Поддержка оставшихся платформ
Развитие DSL обработки доступа
Библиотека примитивов
Средства управления спецификациями
Дописать документацию
35
36
Q&A
АЛЕКСЕЙ ТКАЧЕНКО
ОАО «ПЕЛЕНГ»
TKACHENKO@PELENG.BY, ALEXEY.TKACHENKO@GMAIL.COM
HTTPS://GITHUB.COM/ALEXEY-TKACHENKO/

More Related Content

PPTX
PVS-Studio, решение для разработки современных ресурсоемких приложений
OOO "Program Verification Systems"
 
PPT
Root Conf2009 Fin
Liudmila Li
 
DOC
РусКрипто CTF 2010 Full Disclosure (мастер класс)
Dmitry Evteev
 
PDF
Лекция 3. Векторизация кода (Code vectorization: SSE, AVX)
Mikhail Kurnosov
 
PDF
Семинар 12. Параллельное программирование на MPI (часть 5)
Mikhail Kurnosov
 
PPT
Кратко о Linux
Anthony Shoumikhin
 
PDF
Лекция 3: Векторизация кода (Code vectorization, SIMD, SSE, AVX)
Mikhail Kurnosov
 
ODP
Многопоточность в .NET: Дьявол в деталях
Mikhail Shcherbakov
 
PVS-Studio, решение для разработки современных ресурсоемких приложений
OOO "Program Verification Systems"
 
Root Conf2009 Fin
Liudmila Li
 
РусКрипто CTF 2010 Full Disclosure (мастер класс)
Dmitry Evteev
 
Лекция 3. Векторизация кода (Code vectorization: SSE, AVX)
Mikhail Kurnosov
 
Семинар 12. Параллельное программирование на MPI (часть 5)
Mikhail Kurnosov
 
Кратко о Linux
Anthony Shoumikhin
 
Лекция 3: Векторизация кода (Code vectorization, SIMD, SSE, AVX)
Mikhail Kurnosov
 
Многопоточность в .NET: Дьявол в деталях
Mikhail Shcherbakov
 

What's hot (16)

PDF
Семинар 8. Параллельное программирование на MPI (часть 1)
Mikhail Kurnosov
 
PDF
Использование Time-Stamp Counter для измерения времени выполнения кода на пр...
Mikhail Kurnosov
 
PPT
Prez osob mikroproc
semsemsemsemsem
 
PDF
Nikita Tarakanov - Kernel Pool Overflow from Windows XP to Windows 8
DefconRussia
 
PPTX
Ликбез по Эльбрусу, Константин Трушкин (МЦСТ)
Ontico
 
PDF
Статический анализ: ошибки в медиаплеере и безглючная аська
Tatyanazaxarova
 
PPT
Лекция № 3 Организация ЭВМ и систем
Александр Силантьев
 
PDF
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Mikhail Kurnosov
 
PPT
CUDA Course 2010 at MSU
larhat
 
PPT
Лекция №3 Организация ЭВМ и систем
pianist2317
 
PPT
присяжный Root Conf2009 Beta 1
Liudmila Li
 
PDF
Семинар 9. Параллельное программирование на MPI (часть 2)
Mikhail Kurnosov
 
PPT
Лекция №5 Организация ЭВМ и систем
pianist2317
 
PDF
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Mikhail Kurnosov
 
PDF
Лекция 5: Многопоточное программирование: часть 1 (Multithreading programming...
Mikhail Kurnosov
 
PDF
«Отладка приложений с помощью dtrace» — Станислав Краснояров, Redsteep
e-Legion
 
Семинар 8. Параллельное программирование на MPI (часть 1)
Mikhail Kurnosov
 
Использование Time-Stamp Counter для измерения времени выполнения кода на пр...
Mikhail Kurnosov
 
Prez osob mikroproc
semsemsemsemsem
 
Nikita Tarakanov - Kernel Pool Overflow from Windows XP to Windows 8
DefconRussia
 
Ликбез по Эльбрусу, Константин Трушкин (МЦСТ)
Ontico
 
Статический анализ: ошибки в медиаплеере и безглючная аська
Tatyanazaxarova
 
Лекция № 3 Организация ЭВМ и систем
Александр Силантьев
 
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Mikhail Kurnosov
 
CUDA Course 2010 at MSU
larhat
 
Лекция №3 Организация ЭВМ и систем
pianist2317
 
присяжный Root Conf2009 Beta 1
Liudmila Li
 
Семинар 9. Параллельное программирование на MPI (часть 2)
Mikhail Kurnosov
 
Лекция №5 Организация ЭВМ и систем
pianist2317
 
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Mikhail Kurnosov
 
Лекция 5: Многопоточное программирование: часть 1 (Multithreading programming...
Mikhail Kurnosov
 
«Отладка приложений с помощью dtrace» — Станислав Краснояров, Redsteep
e-Legion
 
Ad

Similar to Исключительная модель памяти. Алексей Ткаченко ➠ CoreHard Autumn 2019 (20)

PDF
1.stm32 core flash rcc
Sergey Savkin
 
PDF
Lab5
ssuser568529
 
DOC
023
JIuc
 
PPTX
Theme 07
pempeshka
 
DOC
23
JIuc
 
PDF
Лекция 4: Оптимизация доступа к памяти (Memory access optimization, caches)
Mikhail Kurnosov
 
PPTX
[DD] 10. Memory
Gabit Altybaev
 
DOC
40
JIuc
 
PDF
Hacking PostgreSQL. Локальная память процессов. Контексты памяти.
Anastasia Lubennikova
 
PDF
C++ STL & Qt. Занятие 11.
Igor Shkulipa
 
PPT
prezlec_Історія.ppt
ssusere2bc36
 
PPT
Лекция №5 Организация ЭВМ и систем
Александр Силантьев
 
PPTX
Презентация 5
Nikita Zablotskiy
 
PDF
C++ весна 2014 лекция 2
Technopark
 
PPT
025
JIuc
 
PPTX
42
JIuc
 
PPT
06. Память Cortex-M3(4)
KamlachPV
 
PDF
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Tatyanazaxarova
 
PDF
Операционные системы
yaevents
 
PDF
Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ...
Yandex
 
1.stm32 core flash rcc
Sergey Savkin
 
023
JIuc
 
Theme 07
pempeshka
 
23
JIuc
 
Лекция 4: Оптимизация доступа к памяти (Memory access optimization, caches)
Mikhail Kurnosov
 
[DD] 10. Memory
Gabit Altybaev
 
40
JIuc
 
Hacking PostgreSQL. Локальная память процессов. Контексты памяти.
Anastasia Lubennikova
 
C++ STL & Qt. Занятие 11.
Igor Shkulipa
 
prezlec_Історія.ppt
ssusere2bc36
 
Лекция №5 Организация ЭВМ и систем
Александр Силантьев
 
Презентация 5
Nikita Zablotskiy
 
C++ весна 2014 лекция 2
Technopark
 
025
JIuc
 
42
JIuc
 
06. Память Cortex-M3(4)
KamlachPV
 
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Tatyanazaxarova
 
Операционные системы
yaevents
 
Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ...
Yandex
 
Ad

More from corehard_by (20)

PPTX
C++ CoreHard Autumn 2018. Создание пакетов для открытых библиотек через conan...
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Что должен знать каждый C++ программист или Как про...
corehard_by
 
PDF
C++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Знай свое "железо": иерархия памяти - Александр Титов
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Информационная безопасность и разработка ПО - Евген...
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Ускорение сборки C++ проектов, способы и последстви...
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Метаклассы: воплощаем мечты в реальность - Сергей С...
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
corehard_by
 
PDF
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
corehard_by
 
PPTX
C++ Corehard Autumn 2018. Обучаем на Python, применяем на C++ - Павел Филонов
corehard_by
 
PDF
C++ CoreHard Autumn 2018. Asynchronous programming with ranges - Ivan Čukić
corehard_by
 
PDF
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
corehard_by
 
PDF
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
corehard_by
 
PDF
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
corehard_by
 
PDF
Как помочь и как помешать компилятору. Андрей Олейников ➠ CoreHard Autumn 2019
corehard_by
 
PDF
Автоматизируй это. Кирилл Тихонов ➠ CoreHard Autumn 2019
corehard_by
 
PDF
Статичный SQL в С++14. Евгений Захаров ➠ CoreHard Autumn 2019
corehard_by
 
C++ CoreHard Autumn 2018. Создание пакетов для открытых библиотек через conan...
corehard_by
 
C++ CoreHard Autumn 2018. Что должен знать каждый C++ программист или Как про...
corehard_by
 
C++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников
corehard_by
 
C++ CoreHard Autumn 2018. Знай свое "железо": иерархия памяти - Александр Титов
corehard_by
 
C++ CoreHard Autumn 2018. Информационная безопасность и разработка ПО - Евген...
corehard_by
 
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
corehard_by
 
C++ CoreHard Autumn 2018. Ускорение сборки C++ проектов, способы и последстви...
corehard_by
 
C++ CoreHard Autumn 2018. Метаклассы: воплощаем мечты в реальность - Сергей С...
corehard_by
 
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
corehard_by
 
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
corehard_by
 
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
corehard_by
 
C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
corehard_by
 
C++ Corehard Autumn 2018. Обучаем на Python, применяем на C++ - Павел Филонов
corehard_by
 
C++ CoreHard Autumn 2018. Asynchronous programming with ranges - Ivan Čukić
corehard_by
 
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
corehard_by
 
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
corehard_by
 
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
corehard_by
 
Как помочь и как помешать компилятору. Андрей Олейников ➠ CoreHard Autumn 2019
corehard_by
 
Автоматизируй это. Кирилл Тихонов ➠ CoreHard Autumn 2019
corehard_by
 
Статичный SQL в С++14. Евгений Захаров ➠ CoreHard Autumn 2019
corehard_by
 

Исключительная модель памяти. Алексей Ткаченко ➠ CoreHard Autumn 2019

  • 2. Об авторе Ведущий разработчик ОАО «Пеленг» Специализируюсь на испытательном оборудовании для космической аппаратуры В свободное время делаю pet-проекты, в том числе embedded Вижу боль embedded-разработчиков и хочу помочь 2
  • 3. План доклада Регистровые аппаратные интерфейсы Имитация аппаратных интерфейсов с помощью механизмов защиты памяти Библиотека ExMM для имитации регистрового аппаратного интерфейс 3
  • 7. Модель ввода-вывода 7 Свойства регистров: • Назначение битов определяется контроллером • Биты не обязательно доступны для чтения/записи (пример – MSR, например EFlags в x86) • Чтение/запись могут быть асимметричными • В общем случае не предполагается хранение содержимого
  • 15. Исходные данные •Подходы при взаимодействии периферийных устройств с программным обеспечением достаточно разнообразны •Память, основанная на ячейках, хранящих информацию, не годится для моделирования всего многообразия аппаратных интерфейсов •Язык реализации многих низкоуровневых драйверов для микроконтроллеров – Си, который имеет не слишком развитые средства абстрагирования, а если их реализовывать, поддержка абстрагирования часто является слишком дорогой из-за роста сложности и снижения быстродействия критического к производительности кода •Многие драйверы уже написаны и в них не были заложены возможности тестирования. 15
  • 16. Постановка задачи •Моделирование поведения на уровне исходников. Полное моделирование поведения всего устройства не предполагается. •Поддержка возможности встраивания в систему непрерывной интеграции для выполнения регрессионных тестов •Работа под операционными системами Windows, Linux, macOS на архитектурах процессоров x86, x86_64, ARM (в т.ч. Thumb и Thumb2), ARM64, Aarch64 (при поддержке соответствующих ОС) •Поддержка одновременной работы множества моделей контроллеров •Простота реализации моделей контроллеров 16
  • 17. Что имеем? Операционные системы могут реагировать на обращение к диапазонам адресов виртуальной памяти: Подкачка Проецирование файлов в память Совместное использование библиотек Выделение памяти по требованию Механизм copy-on-write Ошибка доступа к памяти Операционным системам для работы с виртуализацией памяти требуется наличие аппаратного MMU Операционные системы транслируют аппаратные исключения доступа к памяти MMU (и не только их) в исключения или сигналы в контексте спровоцировавшего процесса Существует возможность перехвата исключений/сигналов в пользовательском процессе 17
  • 18. Что имеем? Windows POSIX Выделение памяти VirtualAlloc mmap Настройка доступа VirtualProtect mprotect Перехват Structured Exception Handling Signals Контекст потока Полный Частичный 18
  • 19. Перехваты чтения и записи После записи регистра необходимо вызвать обработчик модели и выполнить обработку записанного пользовательским кодом в ячейку памяти значения При чтении регистра необходимо вызвать обработчик в модели и предоставить пользовательскому коду значение запрашиваемой ячейки памяти 19
  • 20. Порядок действий при перехвате Перехват записи Перехват чтения При обращении к защищённой области памяти MMU формирует ошибку доступа, которую операционная система транслирует в сигнал SIGSEGV или исключение с кодом EXCEPTION_ACCESS_VIOLATION. Снять защиту с регистрового файла Вызвать перехватчик чтения модели контроллера Включить пошаговое выполнение или установить точку останова на следующей инструкции Снять защиту с регистрового файла Перезапустить инструкцию, вызвавшую исключение После завершения инструкции чтения/записи процессор сгенерирует событие трассировки, которое операционная система транслирует в сигнал SIGTRAP или исключение с кодом EXCEPTION_SINGLE_STEP Отключить трассировку/точку исключения Вызвать перехватчик записи модели контроллера Восстановить исходную защиту памяти и продолжить выполнение программы 20
  • 21. Другие аспекты 1. При начале работы контроллера может требоваться инициализация регистрового файла некоторыми начальными значениями 2. Генерация и обработка прерываний 3. Синхронизация доступа к регистровому файлу 4. Фоновая работа модели периферийного устройства может требовать особой работы с регистровым файлом 5. Необходима поддержка отладки как пользовательского кода (драйвера), так и модели контроллера 21
  • 22. Требования к клиентскому коду 1. Регистровый файл должен быть объявлен как volatile-память 2. Пользовательский код не должен полагаться на абсолютные адреса областей памяти 3. Обработчик прерывания должен быть реализован в отдельной функции, которая может быть вызвана как из обработчика исключения (часто оформленного в виде макроса ISR), так и как функция обратного вызова из библиотечного кода 22
  • 23. Библиотека ExMM Библиотека реализует всё, что описано выше Меньше 2000 строк кода! Open-source, размещена на Github по адресу: https://github.com/Alexey-Tkachenko/ExMM/ Скоро в виде Conan-пакета 23
  • 24. Начало работы 1. Подключить библиотеку: #include <exmm.hpp> using namespace ExMM; 2. Определить структуру регистров: struct Registers { volatile int A; volatile int B; volatile int C; }; 24
  • 25. Начало работы 3. Реализовать класс модели контроллера: struct MyController final : public ControllerBase<HookTypes::ReadWrite, Registers> { void HookRead(volatile Registers* data, size_t offset) override {} void HookWrite(volatile Registers* data, size_t offset) override {} }; 25
  • 26. Начало работы 4. Создать объект контроллера: MyController controller; 5. Получить указатель на регистровый файл: volatile Registers *registers = controller.GetIoArea(); 6. Запустить код в управляемом блоке: ExMM::Run([&registers]() { registers->A = 42; registers->B = 123; registers->C = -1; }); 26
  • 27. Простой перехватчик struct MyController final : public ControllerBase<HookTypes::ReadWrite, Registers> { void HookRead(volatile Registers* data, size_t offset) override { std::cout << "Before read at offset " << std::hex << offset << std::endl; } void HookWrite(volatile Registers* data, size_t offset) override { std::cout << "After write at offset " << std::hex << offset << std::endl; } }; 27
  • 28. Перехватчик, реализующий защёлку struct Registers { volatile uint32_t TimeLo; // Microseconds volatile uint32_t TimeHi; // Integral seconds }; class LatchController final : public ControllerBase<HookTypes::Read, Registers> { | uint32_t latchedLoValue; std::chrono::high_resolution_clock::time_point whenStarted; public: LatchController() : whenStarted(std::chrono::high_resolution_clock::now()), latchedLoValue() {} void HookRead(volatile Registers *data, size_t offset) override; }; 28
  • 29. Перехватчик, реализующий защёлку void LatchController::HookRead(volatile Registers *data, size_t offset) { SwitchField(data, offset) | .Case(&Registers::TimeLo, | [this](auto &timeLo) { timeLo = latchedLoValue; }) | .Case(&Registers::TimeHi, [this](auto &timeHi) { static const std::chrono::seconds oneSecond{1}; const auto elapsed = std::chrono::high_resolution_clock::now() - whenStarted; const auto us = std::chrono::duration_cast<std::chrono::microseconds>(elapsed); const auto seconds = us / oneSecond; | latchedLoValue = static_cast<uint32_t>((us % oneSecond).count()); | timeHi = static_cast<uint32_t>(seconds); }); } 29
  • 30. Поддержка массивов struct Registers { // ... volatile uint32_t Telemetry[4]; }; void SomeController::HookRead(volatile Registers* data, size_t offset) { SwitchField(data, offset) | .CaseArray(&Registers::Telemetry, [this](std::size_t index, auto& tm) { tm = shadowRecord.Words[index]; }); } 30
  • 31. Вложенные агрегаты struct Registers { struct TimerData { uint32_t TriggerTimeHi; // Time when timer triggers, seconds. uint32_t TriggerTimeLo; // Time when timer triggers, microseconds. }; | volatile TimerData Timers[8]; // Сonfiguration. }; void SomeController::HookWrite(volatile Registers *data, size_t offset) { SwitchField(data, offset) | .InsideArray(&Registers::Timers, [](std::size_t index, auto &next) { | next.Case(&Registers::TimerData::TriggerTimeHi, [](auto &value) { ... }) .Case(&Registers::TimerData::TriggerTimeLo, [](auto &value) { value = std::min(uint32_t{value}, 999999u); } ); }); } 31
  • 32. Необработанный доступ void SomeController::HookWrite(Registers *data, size_t offset) { SwitchField(data, offset) .Case(&Registers::ControlWord, [this](auto &value) { ...}) .Case(&Registers::StatusWord, [this](auto &value) { ... }) .InsideArray(&Registers::Timers, [](std::size_t index, auto &next) { ... }) | .Else([data](size_t offset) { std::cout << "((not observed)) " << reinterpret_cast<volatile uint32_t *>(data)[offset / 4] << std::endl; }); } 32
  • 34. Известные проблемы Необработанный доступ на Linux за пределами памяти контроллера завершает процесс Низкая производительность DSL Неполная документация 34
  • 35. Дальнейшие планы Поддержка оставшихся платформ Развитие DSL обработки доступа Библиотека примитивов Средства управления спецификациями Дописать документацию 35
  • 36. 36