From d8804c9ae236c32276a7f9361c138978210b4d37 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 5 Apr 2026 17:13:53 +0300 Subject: [PATCH] Generate README.md, add clock dividers and limiters, load configs from WS client, fix stream per-segment subscriptions according to memory projections mechanism --- .gitignore | 1 + Makefile | 10 +- README.md | 250 +++++++++++++++++++++++++++++++ deps/flatbuffers | 2 +- devices/avr_generic/src/device.c | 2 +- flatbuffers/config/device.fbs | 3 +- glob.toml | 60 -------- hmmmm_scripts | 2 +- inc/base_device.h | 2 + inc/context.h | 3 + inc/streamed.h | 2 + src/base_device.c | 1 + src/compose_device.c | 2 +- src/main.c | 52 +++++-- src/proto/handlers.c | 8 +- src/proto/handlers/config.c | 60 ++++++-- src/proto/handlers/mem.c | 21 +-- src/proto/handlers/stream.c | 5 + src/proto/handlers/ws.c | 19 ++- 19 files changed, 396 insertions(+), 109 deletions(-) create mode 100644 README.md delete mode 100644 glob.toml diff --git a/.gitignore b/.gitignore index 89ef8d5..9e8712f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ build devices .cache *.bin +inc/flatbuf_autogen diff --git a/Makefile b/Makefile index a2e6187..62fc4aa 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ LIBS_HEADERS=deps/ $(OPENSSL_INCLUDE) SYSTEM_INCLUDES=-isystem deps/flatcc/include/ -isystem $(PROTO_INC_DIR)/ STATIC_LIBS=crypto STANDART=c23 -OPTIMIZE=-O3 +OPTIMIZE=-Og TARGET=main FLATCC = deps/flatcc/bin/flatcc @@ -48,7 +48,7 @@ LFLAGS=$(OPTIMIZE) -g $(PEDANTIC_FLAGS) $(DEFINES) $(STATICLIBS_FLAGS) -flto -fu OBJECTS = $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o, $(C_SOURCES)) DEP = $(filter %.d, $(OBJECTS:.o=.d)) -$(info $(DEP)) +#$(info $(DEP)) OBJECTS += $(LIBS) vpath %.c $(sort $(dir $(C_SOURCES))) @@ -56,11 +56,11 @@ vpath %.c $(sort $(dir $(C_SOURCES))) all: build -build: date deps Dir proto target compile_commands +build: date deps Dir proto python-proto target compile_commands rebuild: clean | build -$(info $(DEP)) +#$(info $(DEP)) -include $(DEP) @@ -92,7 +92,7 @@ $(PROTO_STAMP): $(FBS_SOURCES) | ProtoDir BuildDir BuildDir: @mkdir -p $(BUILD_DIR) - $(shell mkdir -p $(dir $(OBJECTS))) + @$(shell mkdir -p $(dir $(OBJECTS))) SrcDir: @mkdir -p $(SRC_DIR) diff --git a/README.md b/README.md new file mode 100644 index 0000000..24f0d2e --- /dev/null +++ b/README.md @@ -0,0 +1,250 @@ +# hmmmm + +**Модульный эмулятор микроконтроллеров с сетевым интерфейсом** + +hmmmm — это эмулятор микроконтроллеров, который позволяет эмулировать AVR и другие архитектуры с возможностью управления через WebSocket. Эмулятор поддерживает динамическую загрузку устройств, композицию сложных устройств и потоковую передачу изменений памяти в реальном времени. + +## Возможности + +- **Эмуляция AVR-микроконтроллеров** — поддержка ~99 инструкций AVR +- **Модульная архитектура** — устройства загружаются как динамические библиотеки (.so) +- **Композиция устройств** — создание сложных устройств через TOML-конфигурацию +- **WebSocket интерфейс** — управление эмуляцией и получение данных в реальном времени +- **Потоковая передача** — подписка на изменения памяти (чтение/запись) +- **Аутентификация** — SHA-512 токен с временным окном (TOTP-подобный) +- **Сегментированная память** — PS (программная), GP_REGS, IO_REGS, DS (данные) + +## Структура проекта + +``` +hmmmm/ +├── src/ # Исходный код эмулятора +│ ├── main.c # WebSocket сервер, главный цикл +│ ├── hmmmm.c # Загрузка динамических библиотек +│ ├── config.c # Парсинг TOML-конфигураций +│ └── proto/ # Обработчики WebSocket-протокола +├── inc/ # Заголовочные файлы +├── devices/ # Реализации эмулируемых устройств +│ ├── avr_generic/ # Универсальный эмулятор AVR +│ └── avr_gpio/ # GPIO устройство +├── flatbuffers/ # FlatBuffers схемы протокола +├── deps/ # Внешние зависимости +├── hmmmm_scripts/ # Python скрипты и утилиты +└── Makefile # Основной файл сборки +``` + +## Требования + +- **GCC** с поддержкой C23 +- **OpenSSL** (для SHA-512) +- **Git** (для клонирования зависимостей) +- **Python 3.12+** (опционально, для скриптов) + +## Сборка + +### 1. Инициализация зависимостей + +```bash +# Клонирование и сборка внешних зависимостей +make deps +``` + +Это клонирует следующие зависимости в `deps/`: +- `tomlc99` — TOML парсер +- `ptQueue` — lock-free очередь +- `wsServer` — WebSocket сервер +- `flatcc` — FlatBuffers runtime для C +- `flatbuffers` — Google FlatBuffers (flatc компилятор) + +### 2. Генерация FlatBuffers кода + +```bash +# Генерация C заголовков из .fbs схем +make proto + +# Генерация Python bindings (опционально) +make python-proto +``` + +### 3. Сборка эмулятора + +```bash +# Основная сборка +make build + +# Полная пересборка +make rebuild + +# Очистка +make clean +``` + +После успешной сборки исполняемый файл будет находиться в `out/main.elf`. + +## Быстрый старт + +### 1. Подготовка конфигурации + +Создайте TOML-файл с конфигурацией эмулятора: + +```toml +# example.toml +[dev] +avr = "devices/avr_generic/AVRrc.toml" + +[clock] +limiter = 16000000 # 16 MHz + +[mem] +# Настройка памяти +``` + +### 2. Запуск эмулятора + +```bash +./out/main.elf example.toml +``` + +Эмулятор запустит WebSocket сервер на порту **8181**. + +### 3. Подключение клиента + +Используйте Python-клиент для подключения: + +```bash +cd ../hmmmm_client_py +poetry install +poetry run python -m model.client +``` + +## Конфигурация + +### TOML-конфигурация устройства + +Пример конфигурации AVR устройства: + +```toml +[device] +type = "avr_generic" +libpath = "devices/avr_generic/AVRrc_build/device.so" +firmware = "test.bin" + +[memory] +ps_size = 65536 # Program space +ds_size = 4096 # Data space +io_regs = 256 # I/O registers +gp_regs = 32 # General purpose registers +``` + +### Композиция устройств + +Сложные устройства создаются через композицию: + +```toml +[dev] +core = "avr_generic.toml" +gpio_a = "avr_gpio.toml" + +[clock] +limiter = 16000000 + +[mem.intercept.PORTA] +base_at = "core" +point_at = "gpio_a" +addr = 0 +seg = "reg_io" +``` + +## Протокол + +Эмулятор использует **FlatBuffers over WebSocket** для обмена сообщениями. + +### Типы сообщений + +#### Клиент → Сервер: +- **AuthRequest** — аутентификация (SHA-512 токен + timestamp) +- **ExecCtrlMessage** — управление эмуляцией (старт/стоп/сброс) +- **MemReadRequest/MemWriteRequest** — операции с памятью +- **StreamRegRequest** — подписка на изменения памяти + +#### Сервер → Клиент: +- **AuthResponse** — подтверждение аутентификации (seat_id) +- **ExecNotifyMessage** — уведомления о состоянии эмуляции +- **MemReadResponse** — данные из памяти +- **StreamDataPush** — потоковые изменения памяти + +### Аутентификация + +```python +import hashlib +import time + +def generate_auth(access_token: str) -> bytes: + now = int(time.time()) + prepared = f'{access_token}{now // 30}' + return hashlib.sha512(prepared.encode()).digest() +``` + +Токен действителен в течение 30 секунд. + +## API устройств + +Каждое устройство должно экспортировать интерфейс `device_lib_t`: + +```c +typedef struct { + uint8_t devType; + device_public_context_t* (*init)(void*, char* errbuf); + uint8_t (*makeDeviceTick)(device_public_context_t* devInfo); + void* extendedHandlers; + void* (*parseSpecsFromConfig)(const conf_dev_t* devConf, char* errbuf); + void (*freeSpecs)(void* specs); + void (*freeDevMem)(device_mem_t* mem); + void (*fillSmartReadSpecs)(void* specs, smart_read_spec_t*, uint64_t); + void (*fillSmartWriteSpecs)(void* specs, smart_write_spec_t*, uint64_t); +} device_lib_t; +``` + +## Отладка + +### Генерация compile_commands.json + +Для интеграции с clangd: + +```bash +./.gen_compile_commands.sh +``` + +### Логирование + +Эмулятор выводит отладочную информацию в stdout. Для подробного логирования можно модифицировать `src/main.c`. + +### GDB + +```bash +gdb ./out/main.elf +(gdb) run example.toml +``` + +## Производительность + +- **Тактовая частота** — до 16 MHz (эмулируемая) +- **WebSocket** — асинхронная отправка сообщений +- **Lock-free очереди** — эффективный межпоточный обмен +- **FlatBuffers** — сериализация с нулевым копированием + +## Известные ограничения + +- Абсолютные пути в конфигурационных файлах (требует замены на относительные) +- Хардкод токена аутентификации (требует выноса в ENV) +- Отсутствие graceful shutdown (обработка SIGINT/SIGTERM) +- Нет unit-тестов для основного кода + +## Лицензия + +Проект разработан @nikto_b. Все права защищены. + +## Контакты + +- Документация: https://about.hmmmm.nikto-b.ru/ +- Автор: @nikto_b diff --git a/deps/flatbuffers b/deps/flatbuffers index 4e582b0..e223d69 160000 --- a/deps/flatbuffers +++ b/deps/flatbuffers @@ -1 +1 @@ -Subproject commit 4e582b0c1d60c55f9a0a90f9740d4a4c48f3b53b +Subproject commit e223d69b36574c4a2b10dbd27761753de81624ab diff --git a/devices/avr_generic/src/device.c b/devices/avr_generic/src/device.c index 59f6c46..b88e772 100644 --- a/devices/avr_generic/src/device.c +++ b/devices/avr_generic/src/device.c @@ -72,7 +72,7 @@ device_mem_t* genDevMem(device_specs_t* devSpec, char* errbuf) void* rawCells = (void*)malloc(memTotalSize); if (rawCells == NULL) { - sprintf(errbuf, "unable to allocate raw memory buf"); + sprintf(errbuf, "unable to allocate raw memory buf %lu bytes", memTotalSize); free(devMem); return NULL; } diff --git a/flatbuffers/config/device.fbs b/flatbuffers/config/device.fbs index 9352dbf..6ef7a1b 100644 --- a/flatbuffers/config/device.fbs +++ b/flatbuffers/config/device.fbs @@ -41,7 +41,8 @@ table DeviceEntry { // Inline device configuration — either base or compose. config: DeviceConfig; - clock: DeviceClockConfig; + //clock: DeviceClockConfig; + clock_divider: uint64 = 1; overrides: [MemSegOverride]; } diff --git a/glob.toml b/glob.toml deleted file mode 100644 index 2193245..0000000 --- a/glob.toml +++ /dev/null @@ -1,60 +0,0 @@ -[dev] -core = "/home/nikto_b/Documents/baum/hmmmm/devices/avr_generic/AVRrc.toml" -# gpio_a = "/home/nikto_b/Documents/baum/hmmmm/devices/avr_gpio/gpio.toml" - -[config.core.mem.ps] -len = 128 - - -[clock] -limiter = 16000000 - -[clock.core] -src = "" -divider = 1 - -[clock.gpio_a] -src = "core" -divider = 2 - - -# [mem.projection.gpio_a.ext_reg_io] -# base_at = "core" -# base_seg = "reg_io" -# projection_shift = 0 - - -[mem.intercept.PORTA] -base_at = "core" -point_at = "gpio_a" -addr = 0 -seg = "reg_io" - - -[mem.intercept.PINA] -base_at = "core" -point_at = "gpio_a" -base_addr = 1 -point_addr = 1 -base_seg = "reg_io" -point_seg = "ext_reg_io" - -[mem.setup.core.ps] -filepath = "/home/nikto_b/Documents/avr_selftests/test.bin" - - -[mem.setup.core.ds] -filepath = "/dev/urandom" -overflow_behaviour = "ignore" - -# - почему си (адресная арифметика, отсутствие мешающих фичей языка, широкое распространение среди разработчеков-железячников) -# - подход к модульности (всё базовое устройство, запускаем комбинированные устройства из базовых и комбинированных) -# - структура базового модуля эмулятора (какие есть варианты полей конфига) -# - структура комбинированного модуля эмулятора (какие есть варианты полей конфига) -# - структура комбинированного модуля эмулятора (какие конфиг вырождается в эмулятор) -# - процесс инициализации модуля (6 этапов инициализации) -# - процесс исполнения модуля (чисто дергаем "makeTick" у каждой dlib'ы) -# - реализация перехватчиков доступа (пример с sbi, диаграмма с тестовым перехватчиком) -# - реализация проецирования памяти (диаграммы с колбасами) -# - тестовая прошивка (селфтест сложения-вычитания) -# - пример исполнения (?) diff --git a/hmmmm_scripts b/hmmmm_scripts index 9cc7b36..1bcda28 160000 --- a/hmmmm_scripts +++ b/hmmmm_scripts @@ -1 +1 @@ -Subproject commit 9cc7b36cbbfbd6324874069add330fcd60839f54 +Subproject commit 1bcda2881a5c063d0b81b1043d0ad8b364e198e5 diff --git a/inc/base_device.h b/inc/base_device.h index f861185..97f7b0a 100644 --- a/inc/base_device.h +++ b/inc/base_device.h @@ -2,6 +2,7 @@ #define __BASE_DEVICE_H__ #include "hmmmm.h" +#include typedef struct { void* specs; @@ -9,6 +10,7 @@ typedef struct { device_public_context_t* ctx; uint64_t clockCycleLimit; uint64_t clockCycleCounter; + uint64_t clockDivider; } device_handle_t; diff --git a/inc/context.h b/inc/context.h index 683f285..e47e21e 100644 --- a/inc/context.h +++ b/inc/context.h @@ -2,6 +2,7 @@ #define __CONTEXT_H__ #include +#include #include "ptQueue/inc/ptQueue.h" #include "wsServer/include/ws.h" @@ -30,11 +31,13 @@ typedef struct { OutgoingBuffers* outBufs; DeviceSegStreamReg** deviceStreamRegs; uint8_t** devicesMem; + size_t** devicesMemSegAddrs; size_t devicesCount; void** deviceHandles; // device_handle_t** — dynamically loaded devices void* interceptCtxs; // contiguous intercept_ctx_t array (freed as single block) size_t interceptCtxCount; flatcc_builder_t stream_builder; + uint64_t simRateLimit; } EmulContext; diff --git a/inc/streamed.h b/inc/streamed.h index 3949f7b..3ba208c 100644 --- a/inc/streamed.h +++ b/inc/streamed.h @@ -12,7 +12,9 @@ typedef struct { ClientContext* clientContext; uint32_t regId; + uint32_t segId; uint64_t startAddr; + uint64_t startGlobalAddr; uint64_t segLen; uint8_t mode; } StreamReg; diff --git a/src/base_device.c b/src/base_device.c index 91d9352..a9e072f 100644 --- a/src/base_device.c +++ b/src/base_device.c @@ -69,6 +69,7 @@ device_handle_t* openBaseDevice(conf_dev_t* devConf, char* errbuf) ret->specs = devSpecs; ret->clockCycleCounter = 0; ret->clockCycleLimit = 0; + ret->clockDivider = 1; return ret; } diff --git a/src/compose_device.c b/src/compose_device.c index 770da1d..5c4d736 100644 --- a/src/compose_device.c +++ b/src/compose_device.c @@ -100,7 +100,7 @@ device_handle_t** openComposeDevice(compose_dev_conf_t* conf, char* errbuf) for(size_t i = 0; i < devIdx; i++) { conf_dev_t* devConf = conf->baseConfigs[i]; - char intErrbuf[1024] = {0}; + char intErrbuf[255] = {0}; device_handle_t* devHandle = openBaseDevice(devConf, intErrbuf); if(devHandle == NULL) { diff --git a/src/main.c b/src/main.c index 35af965..af243e4 100644 --- a/src/main.c +++ b/src/main.c @@ -245,17 +245,17 @@ void mockDevice1(uint8_t* mem, uint64_t* readAddrs, size_t* readAddrsLen, uint64 } -void dispatchStreamSegment(EmulContext* emulContext, StreamReg* reg, uint8_t* mem) +void dispatchStreamSegment(EmulContext* emulContext, StreamReg* reg, device_mem_t* mem) { size_t mlen = 0; uint8_t* msg = fb_build_stream_data_push( &emulContext->stream_builder, UINT64_MAX, reg->regId, *emulContext->clockCounter, - mem + reg->startAddr, reg->segLen, &mlen); + (uint8_t*)(((uint64_t)(mem->cells[reg->segId])) + (uint64_t)reg->startAddr), reg->segLen, &mlen); dispatchOutgoingMessage(emulContext->outBufs, reg->clientContext->clientId, msg, mlen); } -void dispatchMemAccessNotifications(EmulContext* emulContext, DeviceSegStreamReg* deviceRegs, uint8_t* mem, uint64_t* addrs, size_t addrsLen, uint8_t mode) +void dispatchMemAccessNotifications(EmulContext* emulContext, DeviceSegStreamReg* deviceRegs, device_mem_t* mem, uint64_t* addrs, size_t addrsLen, uint8_t mode) { if(deviceRegs->regCount == 0) { @@ -274,7 +274,7 @@ void dispatchMemAccessNotifications(EmulContext* emulContext, DeviceSegStreamReg StreamReg* reg = &deviceRegs->regs[regIdx]; if(reg->mode == mode) { - if(reg->startAddr <= addr && reg->startAddr + reg->segLen >= addr) + if(reg->startGlobalAddr <= addr && reg->startGlobalAddr + reg->segLen >= addr) { uint8_t isDuplicate = 0; for(size_t j = 0; j < dispatchRegsCnt; j++) @@ -307,6 +307,14 @@ void dispatchMemAccessNotifications(EmulContext* emulContext, DeviceSegStreamReg free(dispatchRegs); } + +uint64_t getCurrentUsec() +{ + struct timeval tv; + gettimeofday(&tv,NULL); + return (1000000 * (uint64_t)tv.tv_sec) + (uint64_t)tv.tv_usec; +} + int main(int argc, char** argv) { (void)argc; (void)argv; @@ -320,6 +328,7 @@ int main(int argc, char** argv) size_t deviceCount = 0; DeviceSegStreamReg** deviceStreamRegs = NULL; uint8_t** devicesMem = NULL; + size_t** devicesMemSegmentAddrs = NULL; void** deviceHandlesArr = NULL; uint8_t emulState = EMUL_STATE_STILL; @@ -366,11 +375,13 @@ int main(int argc, char** argv) &outBufs, deviceStreamRegs, devicesMem, + devicesMemSegmentAddrs, deviceCount, deviceHandlesArr, NULL, /* interceptCtxs */ 0, /* interceptCtxCount */ - {0} /* stream_builder — initialized below */ + {0}, /* stream_builder — initialized below */ + 0, }; if (flatcc_builder_init(&emulContext.stream_builder)) { panic("flatcc_builder_init failed\n"); @@ -409,6 +420,8 @@ int main(int argc, char** argv) uint8_t clients_try_timer = 100; + uint64_t lastTickAt = getCurrentUsec(); + while(1) { ClientRegistrationEvent* payload = regQueueTail->payload; @@ -443,7 +456,7 @@ int main(int argc, char** argv) } while(readReqIdx == newWriteIdx) { - my_sleep(1000); + my_sleep(100000); readReqIdx = atomic_load(&outBufs.readRequestIdx); } atomic_store(&outBufs.currWritingIdx, newWriteIdx); @@ -451,22 +464,35 @@ int main(int argc, char** argv) } } - if(emulState == EMUL_STATE_EXEC && emulContext.devicesCount > 0) + uint64_t now = emulContext.simRateLimit > 0? getCurrentUsec() : 0; + + if(emulState == EMUL_STATE_EXEC && emulContext.devicesCount > 0 && (emulContext.simRateLimit == 0 || now - lastTickAt >= 1000000 / emulContext.simRateLimit)) { for (size_t di = 0; di < emulContext.devicesCount; di++) { device_handle_t* dev = (device_handle_t*)emulContext.deviceHandles[di]; - device_mem_t* devMem = dev->ctx->deviceMem; - devMem->memreadLen = 0; - devMem->memwriteLen = 0; - dev->lib->makeDeviceTick(dev->ctx); + if (clockCounter % dev->clockDivider == 0) + { + // printf("clock device %lu\n", di); + device_mem_t* devMem = dev->ctx->deviceMem; + devMem->memreadLen = 0; + devMem->memwriteLen = 0; + + dev->lib->makeDeviceTick(dev->ctx); + + dispatchMemAccessNotifications(&emulContext, emulContext.deviceStreamRegs[di], devMem, devMem->memreadCellAddrs, (size_t)devMem->memreadLen, STREAM_MODE_READ); + dispatchMemAccessNotifications(&emulContext, emulContext.deviceStreamRegs[di], devMem, devMem->memwriteCellAddrs, (size_t)devMem->memwriteLen, STREAM_MODE_WRITE); + } - dispatchMemAccessNotifications(&emulContext, emulContext.deviceStreamRegs[di], devMem->rawCells, devMem->memreadCellAddrs, (size_t)devMem->memreadLen, STREAM_MODE_READ); - dispatchMemAccessNotifications(&emulContext, emulContext.deviceStreamRegs[di], devMem->rawCells, devMem->memwriteCellAddrs, (size_t)devMem->memwriteLen, STREAM_MODE_WRITE); } clockCounter++; + + if(emulContext.simRateLimit > 0) + { + lastTickAt = getCurrentUsec(); + } } else if(!utilizedFlag) { diff --git a/src/proto/handlers.c b/src/proto/handlers.c index c0342ca..eb1fb0f 100644 --- a/src/proto/handlers.c +++ b/src/proto/handlers.c @@ -128,13 +128,13 @@ void handleAllClients(EmulContext* emulContext) if (fbmsg != NULL) { *emulContext->utilizedFlag = 1; - if (hmmmm_ClientMessage_verify_as_root(fbmsg->data, fbmsg->size) == 0) { + // if (hmmmm_ClientMessage_verify_as_root(fbmsg->data, fbmsg->size) == 0) { hmmmm_ClientMessage_table_t cm = hmmmm_ClientMessage_as_root(fbmsg->data); handleIncomingMessage(cm, ctx, emulContext); - } else { - printf("client %lu: dropped malformed FlatBuffer\n", ctx->clientId); - } + // } else { + // printf("client %lu: dropped malformed FlatBuffer\n", ctx->clientId); + // } free(fbmsg->data); free(fbmsg); diff --git a/src/proto/handlers/config.c b/src/proto/handlers/config.c index b9aea10..2e1d015 100644 --- a/src/proto/handlers/config.c +++ b/src/proto/handlers/config.c @@ -1,5 +1,6 @@ #include "proto/handlers/config.h" +#include #include #include #include @@ -122,19 +123,35 @@ static int load_devices_recursive( if (!dc) return -1; device_handle_t* dev = openBaseDevice(dc, errbuf); - freeConf(dc); // freeConf() already calls free(dc) - if (!dev) return -1; + if (!dev) { + freeConf(dc); + return -1; + } + + const uint64_t clockDivider = hmmmm_config_DeviceEntry_clock_divider(entry); + if(clockDivider > 0) + { + dev->clockDivider = clockDivider; + } + + dev->lib->fillSmartReadSpecs(dev->specs, NULL, 0); dev->lib->fillSmartWriteSpecs(dev->specs, NULL, 0); - dev->ctx = dev->lib->init(dev->specs, errbuf); + char initErrBuf[256]; + + dev->ctx = dev->lib->init(dev->specs, initErrBuf); if (!dev->ctx) { + snprintf(errbuf, 1024, "error while loading device %lu: %s", st->count, initErrBuf); closeBaseDevice(dev); free(dev); + freeConf(dc); return -1; } + freeConf(dc); + size_t idx = st->count; st->handles[idx] = dev; @@ -471,6 +488,7 @@ static void free_old_config(EmulContext* emulContext) emulContext->devicesMem = NULL; emulContext->deviceStreamRegs = NULL; emulContext->devicesCount = 0; + emulContext->simRateLimit = 0; } @@ -522,6 +540,8 @@ void handleConfigCtrlMessage( return; } + const uint64_t simRateLimit = hmmmm_config_EmulationConfig_sim_rate_limit(econf); + // Free old config free_old_config(emulContext); @@ -591,10 +611,12 @@ void handleConfigCtrlMessage( // Allocate new arrays for EmulContext size_t dc = st.count; emulContext->devicesCount = dc; + emulContext->simRateLimit = simRateLimit; - emulContext->deviceHandles = calloc(dc, sizeof(void*)); - emulContext->devicesMem = calloc(dc, sizeof(uint8_t*)); - emulContext->deviceStreamRegs = calloc(dc, sizeof(DeviceSegStreamReg*)); + emulContext->deviceHandles = calloc(dc, sizeof(void*)); + emulContext->devicesMem = calloc(dc, sizeof(uint8_t*)); + emulContext->devicesMemSegAddrs = calloc(dc, sizeof(size_t*)); + emulContext->deviceStreamRegs = calloc(dc, sizeof(DeviceSegStreamReg*)); if (!emulContext->deviceHandles || !emulContext->devicesMem || !emulContext->deviceStreamRegs) { @@ -619,16 +641,36 @@ void handleConfigCtrlMessage( return; } - for (size_t i = 0; i < dc; i++) { + for (size_t i = 0; i < dc; i++) + { emulContext->deviceHandles[i] = st.handles[i]; emulContext->devicesMem[i] = st.handles[i]->ctx->deviceMem->rawCells; + + emulContext->devicesMemSegAddrs[i] = calloc(st.seg_counts[i], sizeof(size_t)); + + for(size_t seg_id = 0; seg_id < st.seg_counts[i]; seg_id++) + { + + // size_t segShift = (size_t)(st.handles[i]->ctx->deviceMem->cells[seg_id]) - (size_t)(st.handles[i]->ctx->deviceMem->cells[0]); + size_t segShift = st.handles[i]->ctx->deviceMem->memsegShifts[seg_id]; + emulContext->devicesMemSegAddrs[i][seg_id] = segShift; + } DeviceSegStreamReg* dsr = calloc(1, sizeof(DeviceSegStreamReg)); - if (!dsr) { emulContext->deviceStreamRegs[i] = NULL; continue; } + if (!dsr) + { + emulContext->deviceStreamRegs[i] = NULL; + continue; + } dsr->allocatedSize = 4; dsr->regCount = 0; dsr->regs = calloc(4, sizeof(StreamReg)); - if (!dsr->regs) { free(dsr); emulContext->deviceStreamRegs[i] = NULL; continue; } + if (!dsr->regs) + { + free(dsr); + emulContext->deviceStreamRegs[i] = NULL; + continue; + } emulContext->deviceStreamRegs[i] = dsr; } diff --git a/src/proto/handlers/mem.c b/src/proto/handlers/mem.c index 8cf3a16..c97e102 100644 --- a/src/proto/handlers/mem.c +++ b/src/proto/handlers/mem.c @@ -6,7 +6,7 @@ #include "proto/dial.h" #include "mem_reader.h" -#define DEVICE_MEM_SIZE ((size_t)(256 * 1024)) +// #define DEVICE_MEM_SIZE ((size_t)(256 * 1024)) void handleIncomingMemMessage( @@ -40,10 +40,13 @@ void handleIncomingMemMessage( printf("[MEM/READ] invalid device %u\n", dev_id); return; } - if ((size_t)offset + (size_t)length > DEVICE_MEM_SIZE) { - printf("[MEM/READ] out of bounds\n"); - return; - } + + offset = (uint32_t)(((size_t)offset) + emulContext->devicesMemSegAddrs[dev_id][seg_id]); + + // if ((size_t)offset + (size_t)length > DEVICE_MEM_SIZE) { + // printf("[MEM/READ] out of bounds\n"); + // return; + // } const uint8_t* base = emulContext->devicesMem[dev_id]; size_t out_len; @@ -73,10 +76,10 @@ void handleIncomingMemMessage( printf("[MEM/WRITE] invalid device %u\n", dev_id); return; } - if ((size_t)offset + data_len > DEVICE_MEM_SIZE) { - printf("[MEM/WRITE] out of bounds\n"); - return; - } + // if ((size_t)offset + data_len > DEVICE_MEM_SIZE) { + // printf("[MEM/WRITE] out of bounds\n"); + // return; + // } uint8_t* base = emulContext->devicesMem[dev_id]; memcpy(base + offset, data, data_len); diff --git a/src/proto/handlers/stream.c b/src/proto/handlers/stream.c index 139f1ac..ca48b9a 100644 --- a/src/proto/handlers/stream.c +++ b/src/proto/handlers/stream.c @@ -1,5 +1,6 @@ #include "proto/handlers/stream.h" +#include #include #include #include "streamed.h" @@ -104,11 +105,15 @@ void handleIncomingStreamMessage( deviceRegs->allocatedSize = new_size; } + uint64_t globalOffset = (((size_t)offset) + emulContext->devicesMemSegAddrs[dev_id][seg_id]); + uint32_t reg_id = ctx->streamRegIterator++; StreamReg* reg = &deviceRegs->regs[deviceRegs->regCount++]; reg->clientContext = ctx; reg->regId = reg_id; + reg->segId = seg_id; reg->startAddr = (uint64_t)offset; + reg->startGlobalAddr = globalOffset; reg->segLen = (uint64_t)length; reg->mode = (uint8_t)mode; diff --git a/src/proto/handlers/ws.c b/src/proto/handlers/ws.c index 1f9cfff..bb8ea70 100644 --- a/src/proto/handlers/ws.c +++ b/src/proto/handlers/ws.c @@ -2,6 +2,7 @@ #include "proto/handlers.h" #include +#include #include "panic.h" #include "my_mutex.h" #include "proto/enums.h" @@ -112,10 +113,20 @@ void onWsMessage( } // Verify the FlatBuffer before queuing - if (hmmmm_ClientMessage_verify_as_root(msg, (size_t)size)) { - printf("Client %lu sent invalid FlatBuffer, dropping\n", client); - return; - } + // if (hmmmm_ClientMessage_verify_as_root(msg, size)) { + // printf("Client %lu sent invalid FlatBuffer, dropping\n", client); + + // FILE *write_ptr; + + // write_ptr = fopen("/tmp/last_failed_packet.bin","wb"); // w for write, b for binary + // NULL_GUARD(write_ptr); + + // fwrite(msg,size,1,write_ptr); // write 10 bytes from our buffer + // // free(write_ptr); + // fclose(write_ptr); + + // return; + // } // Copy bytes — the WS buffer is only valid for this callback's duration FbMessage* fbmsg = malloc(sizeof(FbMessage));