feat: add projection and intercept support, remove TOML, fix freeDevMem symbol bug
- Remove TOML dependency from Makefile and compose_device.c - Implement projection support in config handler: remap device memory segments between devices via cells[] pointer reassignment - Implement intercept support: shadow_copy (write to both devices) and shadow_replace (redirect read/write to another device) modes using smartAddr handler infrastructure - Fix critical bug in hmmmm.c: freeDevMem was loaded from "freeDevSpecs" symbol instead of "freeDevMem", causing segfault on config reload - Add intercept context lifecycle management to EmulContext Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
28
AVRrc.toml
28
AVRrc.toml
@@ -1,28 +0,0 @@
|
|||||||
[dev]
|
|
||||||
libpath = "/home/nikto_b/Documents/baum/hmmmm/devices/avr_generic/AVRrc_build/device.so"
|
|
||||||
|
|
||||||
|
|
||||||
[mem]
|
|
||||||
|
|
||||||
[mem.ps]
|
|
||||||
start = 0
|
|
||||||
len = 1024
|
|
||||||
wordLen = 2
|
|
||||||
executable = true
|
|
||||||
|
|
||||||
[mem.reg_gp]
|
|
||||||
start = 2048
|
|
||||||
len = 32
|
|
||||||
wordLen = 1
|
|
||||||
|
|
||||||
[mem.reg_io]
|
|
||||||
start = 2080
|
|
||||||
len = 255
|
|
||||||
wordLen = 1
|
|
||||||
|
|
||||||
[mem.ds]
|
|
||||||
start = 2335
|
|
||||||
len = 65535
|
|
||||||
wordLen = 1
|
|
||||||
|
|
||||||
|
|
||||||
2
Makefile
2
Makefile
@@ -4,7 +4,7 @@ SRC_DIR=src
|
|||||||
INC_DIR=inc
|
INC_DIR=inc
|
||||||
CC=gcc
|
CC=gcc
|
||||||
OBJDUMP=objdump
|
OBJDUMP=objdump
|
||||||
LIBS=deps/tomlc99/libtoml.a deps/ptQueue/out/ptQueue.a deps/wsServer/libws.a deps/flatcc/lib/libflatccrt.a
|
LIBS=deps/ptQueue/out/ptQueue.a deps/wsServer/libws.a deps/flatcc/lib/libflatccrt.a
|
||||||
LIBS_HEADERS=deps/ $(OPENSSL_INCLUDE)
|
LIBS_HEADERS=deps/ $(OPENSSL_INCLUDE)
|
||||||
# flatcc runtime and generated reader headers use const-dropping casts;
|
# flatcc runtime and generated reader headers use const-dropping casts;
|
||||||
# include both as system headers so -Wcast-qual doesn't apply to them
|
# include both as system headers so -Wcast-qual doesn't apply to them
|
||||||
|
|||||||
23
gpio.toml
23
gpio.toml
@@ -1,23 +0,0 @@
|
|||||||
[dev]
|
|
||||||
libpath = "avr_gpio/out/device.so"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[mem.ext_reg_io]
|
|
||||||
start = 0
|
|
||||||
len = 255
|
|
||||||
wordLen = 1
|
|
||||||
|
|
||||||
[mem.extstate]
|
|
||||||
start = 256
|
|
||||||
len = 1
|
|
||||||
wordLen = 1
|
|
||||||
|
|
||||||
[mem.variables]
|
|
||||||
PIN = 0
|
|
||||||
PORT = 1
|
|
||||||
DDR = 2
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -35,7 +35,6 @@ typedef struct {
|
|||||||
device_handle_t** devHandlers;
|
device_handle_t** devHandlers;
|
||||||
} compose_dev_handle_t;
|
} compose_dev_handle_t;
|
||||||
|
|
||||||
compose_dev_conf_t* openComposeDeviceConfig(const char* configPath, char* errbuf);
|
|
||||||
device_handle_t** openComposeDevice(compose_dev_conf_t* conf, char* errbuf);
|
device_handle_t** openComposeDevice(compose_dev_conf_t* conf, char* errbuf);
|
||||||
|
|
||||||
#endif // ifndef __COMPOSE_DEVICE_H__
|
#endif // ifndef __COMPOSE_DEVICE_H__
|
||||||
@@ -32,6 +32,8 @@ typedef struct {
|
|||||||
uint8_t** devicesMem;
|
uint8_t** devicesMem;
|
||||||
size_t devicesCount;
|
size_t devicesCount;
|
||||||
void** deviceHandles; // device_handle_t** — dynamically loaded devices
|
void** deviceHandles; // device_handle_t** — dynamically loaded devices
|
||||||
|
void** interceptCtxs; // intercept_ctx_t** — heap-allocated intercept contexts
|
||||||
|
size_t interceptCtxCount;
|
||||||
flatcc_builder_t stream_builder;
|
flatcc_builder_t stream_builder;
|
||||||
} EmulContext;
|
} EmulContext;
|
||||||
|
|
||||||
|
|||||||
@@ -2,34 +2,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
#include "tomlc99/toml.h"
|
|
||||||
|
|
||||||
#include "base_device.h"
|
#include "base_device.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
device_handle_t* openBaseDeviceFromConfig(const char* configPath, char* errbuf)
|
|
||||||
{
|
|
||||||
char intErrbuf[1024];
|
|
||||||
|
|
||||||
conf_dev_t *devConf = openBaseDeviceConfig(configPath, intErrbuf);
|
|
||||||
if (devConf == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to read device config: %s", intErrbuf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
device_handle_t* ret = openBaseDevice(devConf, intErrbuf);
|
|
||||||
|
|
||||||
if(ret == NULL)
|
|
||||||
{
|
|
||||||
freeConf(devConf);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void closeBaseDevice(device_handle_t* devHandle)
|
void closeBaseDevice(device_handle_t* devHandle)
|
||||||
{
|
{
|
||||||
if(devHandle->ctx != NULL)
|
if(devHandle->ctx != NULL)
|
||||||
@@ -90,186 +65,3 @@ device_handle_t* openBaseDevice(conf_dev_t* devConf, char* errbuf)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
conf_mem_seg_t** parseMemToml(const toml_table_t* memTable)
|
|
||||||
{
|
|
||||||
uint16_t memSegIdx = 0;
|
|
||||||
const char* memSegKey = toml_key_in(memTable, 0);
|
|
||||||
while (memSegKey && memSegIdx < 0xFFFF)
|
|
||||||
{
|
|
||||||
memSegIdx++;
|
|
||||||
memSegKey = toml_key_in(memTable, memSegIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
conf_mem_seg_t** segConfigs = malloc(sizeof(conf_mem_seg_t*) * ((size_t)memSegIdx + 1));
|
|
||||||
if (segConfigs == NULL)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
segConfigs[memSegIdx] = NULL;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < memSegIdx; i++)
|
|
||||||
{
|
|
||||||
segConfigs[i] = (conf_mem_seg_t*)malloc(sizeof(conf_mem_seg_t));
|
|
||||||
memSegKey = toml_key_in(memTable, (int)i);
|
|
||||||
|
|
||||||
if (segConfigs[i] == NULL || memSegKey == NULL)
|
|
||||||
{
|
|
||||||
if (segConfigs[i] != NULL)
|
|
||||||
{
|
|
||||||
free(segConfigs[i]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
}
|
|
||||||
for(size_t j = 0; j < i; j++)
|
|
||||||
{
|
|
||||||
free(segConfigs[j]->name);
|
|
||||||
free(segConfigs[j]);
|
|
||||||
}
|
|
||||||
free(segConfigs);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
segConfigs[i]->name = (char*)malloc(strlen(memSegKey) + 1);
|
|
||||||
if (segConfigs[i]->name == NULL)
|
|
||||||
{
|
|
||||||
for(size_t j = 0; j <= i; j++)
|
|
||||||
{
|
|
||||||
if (j < i)
|
|
||||||
free(segConfigs[j]->name);
|
|
||||||
free(segConfigs[j]);
|
|
||||||
}
|
|
||||||
free(segConfigs);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
strcpy(segConfigs[i]->name, memSegKey);
|
|
||||||
|
|
||||||
toml_table_t* segTable = toml_table_in(memTable, memSegKey);
|
|
||||||
if (segTable == NULL)
|
|
||||||
{
|
|
||||||
|
|
||||||
for(size_t j = 0; j <= i; j++)
|
|
||||||
{
|
|
||||||
free(segConfigs[j]->name);
|
|
||||||
free(segConfigs[j]);
|
|
||||||
}
|
|
||||||
free(segConfigs);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
toml_datum_t startDatum = toml_int_in(segTable, "start");
|
|
||||||
toml_datum_t lenDatum = toml_int_in(segTable, "len");
|
|
||||||
toml_datum_t wordLenDatum = toml_int_in(segTable, "wordLen");
|
|
||||||
toml_datum_t executableDatum = toml_bool_in(segTable, "executable");
|
|
||||||
|
|
||||||
if (!startDatum.ok || !lenDatum.ok || !wordLenDatum.ok)
|
|
||||||
{
|
|
||||||
for(size_t j = 0; j <= i; j++)
|
|
||||||
{
|
|
||||||
free(segConfigs[j]->name);
|
|
||||||
free(segConfigs[j]);
|
|
||||||
}
|
|
||||||
free(segConfigs);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
segConfigs[i]->start = (size_t)startDatum.u.i;
|
|
||||||
segConfigs[i]->len = (size_t)lenDatum.u.i;
|
|
||||||
segConfigs[i]->wordLen = (uint8_t)wordLenDatum.u.i;
|
|
||||||
segConfigs[i]->isExecutable = 0;
|
|
||||||
if (executableDatum.ok)
|
|
||||||
{
|
|
||||||
segConfigs[i]->isExecutable = executableDatum.u.b != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return segConfigs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
conf_dev_t* openBaseDeviceConfig(const char* configPath, char* errbuf)
|
|
||||||
{
|
|
||||||
conf_dev_t* ret = malloc(sizeof(conf_dev_t));
|
|
||||||
if (ret == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to allocate device conf struct");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret->id = NULL;
|
|
||||||
ret->clockDivider = 1;
|
|
||||||
ret->clockMultipler = 1;
|
|
||||||
ret->clockId = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
ret->memConf = malloc(sizeof(conf_mem_t));
|
|
||||||
if (ret->memConf == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to allocate device memory conf struct");
|
|
||||||
free(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char intErrbuf[1024];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
FILE *fp = fopen (configPath, "rb");
|
|
||||||
if (!fp) {
|
|
||||||
sprintf(errbuf, "unable to open config file %s", configPath);
|
|
||||||
free(ret->memConf);
|
|
||||||
free(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
toml_table_t* conf = toml_parse_file(fp, intErrbuf, sizeof(intErrbuf));
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
if (!conf) {
|
|
||||||
sprintf(errbuf, "cannot parse - %s", intErrbuf);
|
|
||||||
free(ret->memConf);
|
|
||||||
free(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
toml_table_t* devBlock = toml_table_in(conf, "dev");
|
|
||||||
if (!devBlock) {
|
|
||||||
sprintf(errbuf, "missing [dev]");
|
|
||||||
free(ret->memConf);
|
|
||||||
free(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
toml_table_t* memTable = toml_table_in(conf, "mem");
|
|
||||||
if (!memTable) {
|
|
||||||
sprintf(errbuf, "missing [mem]");
|
|
||||||
free(ret->memConf);
|
|
||||||
free(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
toml_datum_t libpathBlock = toml_string_in(devBlock, "libpath");
|
|
||||||
if (!libpathBlock.ok) {
|
|
||||||
sprintf(errbuf, "unable to read dev.libpath");
|
|
||||||
free(ret->memConf);
|
|
||||||
free(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
conf_mem_seg_t** memSegConfs = parseMemToml(memTable);
|
|
||||||
if (memSegConfs == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to parse mem segments");
|
|
||||||
free(ret->memConf);
|
|
||||||
free(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret->memConf->memSegConfs = memSegConfs;
|
|
||||||
ret->libPath = libpathBlock.u.s;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,31 +2,10 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "tomlc99/toml.h"
|
|
||||||
|
|
||||||
#include "base_device.h"
|
#include "base_device.h"
|
||||||
#include "compose_device.h"
|
#include "compose_device.h"
|
||||||
|
|
||||||
|
|
||||||
// void fillDevClockConfig(const toml_table_t* clockTable, conf_dev_t** devConfs)
|
|
||||||
// {
|
|
||||||
// uint16_t clockSegIdx = 0;
|
|
||||||
// uint16_t clockSegSkips = 0;
|
|
||||||
// const char* clockSegKey = toml_key_in(clockTable, 0);
|
|
||||||
// while (clockSegKey && (clockSegIdx + clockSegSkips) < 0xFFFF)
|
|
||||||
// {
|
|
||||||
// clockSegKey = toml_key_in(clockTable, clockSegIdx + clockSegSkips + 1);
|
|
||||||
// if(strcmp(clockSegKey, "limiter") != 0)
|
|
||||||
// {
|
|
||||||
// clockSegIdx++;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// clockSegSkips++;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
char** appendId(char** prev, const char* cur, char* errbuf)
|
char** appendId(char** prev, const char* cur, char* errbuf)
|
||||||
{
|
{
|
||||||
if(prev == NULL)
|
if(prev == NULL)
|
||||||
@@ -40,12 +19,12 @@ char** appendId(char** prev, const char* cur, char* errbuf)
|
|||||||
prev[0] = NULL;
|
prev[0] = NULL;
|
||||||
prev[1] = NULL;
|
prev[1] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t clockIdLen = 0;
|
size_t clockIdLen = 0;
|
||||||
while (prev[clockIdLen] != NULL){clockIdLen++;}
|
while (prev[clockIdLen] != NULL){clockIdLen++;}
|
||||||
|
|
||||||
clockIdLen++;
|
clockIdLen++;
|
||||||
|
|
||||||
char** new = realloc(prev, sizeof(char*) * (clockIdLen + 1));
|
char** new = realloc(prev, sizeof(char*) * (clockIdLen + 1));
|
||||||
|
|
||||||
if(new == NULL)
|
if(new == NULL)
|
||||||
@@ -70,131 +49,6 @@ char** appendId(char** prev, const char* cur, char* errbuf)
|
|||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
conf_dev_t** parseDevToml(const toml_table_t* devTable, const toml_table_t* clockTable, char* errbuf)
|
|
||||||
{
|
|
||||||
uint16_t devSegIdx = 0;
|
|
||||||
const char* devSegKey = toml_key_in(devTable, 0);
|
|
||||||
while (devSegKey && devSegIdx < 0xFFFF)
|
|
||||||
{
|
|
||||||
devSegIdx++;
|
|
||||||
devSegKey = toml_key_in(devTable, devSegIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
conf_dev_t** deviceConfigs = malloc(sizeof(conf_dev_t*) * (devSegIdx + 1));
|
|
||||||
if(deviceConfigs == NULL)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
deviceConfigs[devSegIdx] = NULL;
|
|
||||||
|
|
||||||
for(size_t i = 0; i < devSegIdx; i++)
|
|
||||||
{
|
|
||||||
devSegKey = toml_key_in(devTable, (int)i);
|
|
||||||
if(devSegKey == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to load device key %lu", i);
|
|
||||||
for(size_t j = 0; j < i; j++)
|
|
||||||
{
|
|
||||||
freeConf(deviceConfigs[j]);
|
|
||||||
free(deviceConfigs[j]);
|
|
||||||
}
|
|
||||||
free(deviceConfigs);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
toml_datum_t devpathDatum = toml_string_in(devTable, devSegKey);
|
|
||||||
if(!devpathDatum.ok || !devpathDatum.u.s)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to get device path for %s", devSegKey);
|
|
||||||
|
|
||||||
for(size_t j = 0; j < i; j++)
|
|
||||||
{
|
|
||||||
freeConf(deviceConfigs[j]);
|
|
||||||
free(deviceConfigs[j]);
|
|
||||||
}
|
|
||||||
free(deviceConfigs);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
char intErrbuf[1024];
|
|
||||||
|
|
||||||
conf_dev_t* conf = openBaseDeviceConfig(devpathDatum.u.s, intErrbuf);
|
|
||||||
if(conf == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to load config for %s: %s", devSegKey, intErrbuf);
|
|
||||||
|
|
||||||
for(size_t j = 0; j < i; j++)
|
|
||||||
{
|
|
||||||
freeConf(deviceConfigs[j]);
|
|
||||||
free(deviceConfigs[j]);
|
|
||||||
}
|
|
||||||
free(deviceConfigs);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
conf->id = NULL;
|
|
||||||
conf->id = appendId(conf->id, devSegKey, intErrbuf);
|
|
||||||
|
|
||||||
|
|
||||||
if(conf->id == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to allocate device %s name field", devSegKey);
|
|
||||||
for(size_t j = 0; j <= i; j++)
|
|
||||||
{
|
|
||||||
freeConf(deviceConfigs[j]);
|
|
||||||
free(deviceConfigs[j]);
|
|
||||||
}
|
|
||||||
free(deviceConfigs);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
deviceConfigs[i] = conf;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(clockTable != NULL)
|
|
||||||
{
|
|
||||||
for(size_t i = 0; i < devSegIdx; i++)
|
|
||||||
{
|
|
||||||
conf_dev_t* conf = deviceConfigs[i];
|
|
||||||
toml_table_t* devClockTable = toml_table_in(clockTable, conf->id[0]);
|
|
||||||
if(devClockTable == NULL)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
toml_datum_t dividerDatum = toml_int_in(devClockTable, "divider");
|
|
||||||
if(dividerDatum.ok)
|
|
||||||
{
|
|
||||||
conf->clockDivider = (uint64_t)dividerDatum.u.i;
|
|
||||||
}
|
|
||||||
toml_datum_t multiplerDatum = toml_int_in(devClockTable, "multipler");
|
|
||||||
if(multiplerDatum.ok)
|
|
||||||
{
|
|
||||||
conf->clockMultipler = (uint64_t)multiplerDatum.u.i;
|
|
||||||
}
|
|
||||||
|
|
||||||
toml_datum_t srcDatum = toml_string_in(devClockTable, "src");
|
|
||||||
if(srcDatum.ok && srcDatum.u.s != NULL)
|
|
||||||
{
|
|
||||||
char intErrbuf[1024] = {0};
|
|
||||||
conf->clockId = appendId(conf->clockId, srcDatum.u.s, intErrbuf);
|
|
||||||
if(conf->clockId == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to append clock id for %s: %s", conf->id[0], intErrbuf);
|
|
||||||
for(size_t j = 0; j <= i; j++)
|
|
||||||
{
|
|
||||||
freeConf(deviceConfigs[j]);
|
|
||||||
free(deviceConfigs[j]);
|
|
||||||
}
|
|
||||||
free(deviceConfigs);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return deviceConfigs;
|
|
||||||
}
|
|
||||||
void freeProjectionConfig(projection_conf_t* conf)
|
void freeProjectionConfig(projection_conf_t* conf)
|
||||||
{
|
{
|
||||||
if(conf == NULL)
|
if(conf == NULL)
|
||||||
@@ -228,264 +82,6 @@ void freeProjectionConfigs(projection_conf_t** confs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
projection_conf_t* parseDeviceProjectionConf(const toml_table_t* deviceProjectionTable, char* errbuf)
|
|
||||||
{
|
|
||||||
toml_datum_t baseAtDatum = toml_string_in(deviceProjectionTable, "base_at");
|
|
||||||
if(!baseAtDatum.ok || baseAtDatum.u.s == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "missing 'base_at'");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
toml_datum_t baseSegDatum = toml_string_in(deviceProjectionTable, "base_seg");
|
|
||||||
if(!baseSegDatum.ok || baseSegDatum.u.s == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "missing 'base_seg'");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
toml_datum_t projectionShiftDatum = toml_int_in(deviceProjectionTable, "projection_shift");
|
|
||||||
|
|
||||||
char intErrbuf[1024] = {0};
|
|
||||||
|
|
||||||
projection_conf_t* ret = malloc(sizeof(projection_conf_t));
|
|
||||||
if(ret == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to allocate projection conf");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
ret->baseAt = NULL;
|
|
||||||
ret->baseSeg = NULL;
|
|
||||||
ret->target = NULL;
|
|
||||||
ret->projectionShift = 0;
|
|
||||||
|
|
||||||
if(projectionShiftDatum.ok)
|
|
||||||
{
|
|
||||||
ret->projectionShift = (uint64_t)projectionShiftDatum.u.i;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret->baseAt = appendId(ret->baseAt, baseAtDatum.u.s, intErrbuf);
|
|
||||||
if(ret->baseAt == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to append base_at id");
|
|
||||||
freeProjectionConfig(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
ret->baseSeg = malloc(strlen(baseSegDatum.u.s));
|
|
||||||
if(ret->baseSeg == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to fill base_seg");
|
|
||||||
freeProjectionConfig(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
strcpy(ret->baseSeg, baseSegDatum.u.s);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
projection_conf_t** parseDeviceProjectionConfs(const toml_table_t* deviceProjectionsTable, char* errbuf)
|
|
||||||
{
|
|
||||||
uint16_t projSegIdx = 0;
|
|
||||||
const char* projSegKey = toml_key_in(deviceProjectionsTable, 0);
|
|
||||||
while (projSegKey && projSegIdx < 0xFFFF)
|
|
||||||
{
|
|
||||||
projSegIdx++;
|
|
||||||
projSegKey = toml_key_in(deviceProjectionsTable, projSegIdx);
|
|
||||||
}
|
|
||||||
char intErrbuf[1024] = {0};
|
|
||||||
|
|
||||||
projection_conf_t** ret = malloc(sizeof(projection_conf_t*) * (projSegIdx + 1));
|
|
||||||
if(ret == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to allocate device projections confs");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(size_t i = 0; i <= projSegIdx; i++){ret[i] = NULL;}
|
|
||||||
|
|
||||||
for(size_t i = 0; i < projSegIdx; i++)
|
|
||||||
{
|
|
||||||
projSegKey = toml_key_in(deviceProjectionsTable, (int)i);
|
|
||||||
if(projSegKey == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to load device projection key %lu", i);
|
|
||||||
freeProjectionConfigs(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
toml_table_t* projTable = toml_table_in(deviceProjectionsTable, projSegKey);
|
|
||||||
if(projTable == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to open device %s projection table", projSegKey);
|
|
||||||
freeProjectionConfigs(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret[i] = parseDeviceProjectionConf(projTable, intErrbuf);
|
|
||||||
if(ret[i] == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to load device %s projection configs: %s", projSegKey, intErrbuf);
|
|
||||||
freeProjectionConfigs(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret[i]->target = appendId(ret[i]->target, projSegKey, intErrbuf);
|
|
||||||
if(ret[i]->target == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to append projection target id: %s", intErrbuf);
|
|
||||||
freeProjectionConfigs(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
projection_conf_t** parseProjectionConfs(const toml_table_t* projectionTable, char* errbuf)
|
|
||||||
{
|
|
||||||
uint16_t devicesProjSegIdx = 0;
|
|
||||||
const char* devicesProjSegKey = toml_key_in(projectionTable, 0);
|
|
||||||
while (devicesProjSegKey && devicesProjSegIdx < 0xFFFF)
|
|
||||||
{
|
|
||||||
devicesProjSegIdx++;
|
|
||||||
devicesProjSegKey = toml_key_in(projectionTable, devicesProjSegIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char intErrbuf[1024] = {0};
|
|
||||||
|
|
||||||
size_t totalRetSize = 0;
|
|
||||||
projection_conf_t** ret = malloc(sizeof(projection_conf_t*));
|
|
||||||
if(ret == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to allocate base projection conf array");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
ret[0] = NULL;
|
|
||||||
|
|
||||||
for(size_t i = 0; i < devicesProjSegIdx; i++)
|
|
||||||
{
|
|
||||||
devicesProjSegKey = toml_key_in(projectionTable, (int)i);
|
|
||||||
if(devicesProjSegKey == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to load proj key %lu", i);
|
|
||||||
freeProjectionConfigs(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
toml_table_t* deviceProjTable = toml_table_in(projectionTable, devicesProjSegKey);
|
|
||||||
if(deviceProjTable == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to open device projection table");
|
|
||||||
freeProjectionConfigs(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
projection_conf_t** devProjections = parseDeviceProjectionConfs(deviceProjTable, intErrbuf);
|
|
||||||
|
|
||||||
if(devProjections == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to parse device %s projection rules: %s", devicesProjSegKey, intErrbuf);
|
|
||||||
freeProjectionConfigs(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
size_t dlen = 0;
|
|
||||||
while(devProjections[dlen] != NULL)
|
|
||||||
{
|
|
||||||
devProjections[dlen]->target = appendId(devProjections[dlen]->target, devicesProjSegKey, intErrbuf);
|
|
||||||
if(devProjections[dlen]->target == NULL)
|
|
||||||
{
|
|
||||||
freeProjectionConfigs(ret);
|
|
||||||
freeProjectionConfigs(devProjections);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
dlen++;
|
|
||||||
}
|
|
||||||
ret = realloc(ret, sizeof(projection_conf_t*) * (dlen + totalRetSize + 1));
|
|
||||||
if(ret == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to reallocate full projection array");
|
|
||||||
freeProjectionConfigs(devProjections);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
for(size_t i = 0; i <= dlen; i++)
|
|
||||||
{
|
|
||||||
ret[totalRetSize + i] = devProjections[i];
|
|
||||||
}
|
|
||||||
totalRetSize += dlen;
|
|
||||||
ret[totalRetSize] = NULL;
|
|
||||||
free(devProjections);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
compose_dev_conf_t* openComposeDeviceConfig(const char* configPath, char* errbuf)
|
|
||||||
{
|
|
||||||
compose_dev_conf_t* ret = malloc(sizeof(compose_dev_conf_t));
|
|
||||||
|
|
||||||
if(ret == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to allocate device struct");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char intErrbuf[1024] = {0};
|
|
||||||
FILE *fp = fopen (configPath, "rb");
|
|
||||||
if (!fp) {
|
|
||||||
sprintf(errbuf, "unable to open config file %s", configPath);
|
|
||||||
free(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
toml_table_t* conf = toml_parse_file(fp, intErrbuf, sizeof(intErrbuf));
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
|
|
||||||
toml_table_t* devTable = toml_table_in(conf, "dev");
|
|
||||||
if (!devTable) {
|
|
||||||
sprintf(errbuf, "missing [dev]");
|
|
||||||
free(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
ret->projections = NULL;
|
|
||||||
|
|
||||||
toml_table_t* memTable = toml_table_in(conf, "mem");
|
|
||||||
if(memTable)
|
|
||||||
{
|
|
||||||
toml_table_t* projectionTable = toml_table_in(memTable, "projection");
|
|
||||||
if(projectionTable)
|
|
||||||
{
|
|
||||||
ret->projections = parseProjectionConfs(projectionTable, intErrbuf);
|
|
||||||
if(ret->projections == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to load projections: %s", intErrbuf);
|
|
||||||
free(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
toml_table_t* clockTable = toml_table_in(conf, "clock");
|
|
||||||
|
|
||||||
|
|
||||||
conf_dev_t** devHandlers = parseDevToml(devTable, clockTable, intErrbuf);
|
|
||||||
|
|
||||||
if(devHandlers == NULL)
|
|
||||||
{
|
|
||||||
sprintf(errbuf, "unable to load devices configs: %s", intErrbuf);
|
|
||||||
freeProjectionConfigs(ret->projections);
|
|
||||||
free(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret->baseConfigs = devHandlers;
|
|
||||||
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
device_handle_t** openComposeDevice(compose_dev_conf_t* conf, char* errbuf)
|
device_handle_t** openComposeDevice(compose_dev_conf_t* conf, char* errbuf)
|
||||||
{
|
{
|
||||||
size_t devIdx = 0;
|
size_t devIdx = 0;
|
||||||
@@ -523,7 +119,3 @@ device_handle_t** openComposeDevice(compose_dev_conf_t* conf, char* errbuf)
|
|||||||
|
|
||||||
return devHandlers;
|
return devHandlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ device_lib_t* loadDeviceLib(const char *libpath, char* errbuf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_dlib_freeDevMem_t _dlib_freeDevMem = (_dlib_freeDevMem_t)(uintptr_t)dlsym(handle, "freeDevSpecs");
|
_dlib_freeDevMem_t _dlib_freeDevMem = (_dlib_freeDevMem_t)(uintptr_t)dlsym(handle, "freeDevMem");
|
||||||
|
|
||||||
const char *dlib_freeDevMem_error = dlerror();
|
const char *dlib_freeDevMem_error = dlerror();
|
||||||
if (dlib_freeDevMem_error) {
|
if (dlib_freeDevMem_error) {
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
|
|
||||||
|
|
||||||
#include "tomlc99/toml.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -369,6 +368,8 @@ int main(int argc, char** argv)
|
|||||||
devicesMem,
|
devicesMem,
|
||||||
deviceCount,
|
deviceCount,
|
||||||
deviceHandlesArr,
|
deviceHandlesArr,
|
||||||
|
NULL, /* interceptCtxs */
|
||||||
|
0, /* interceptCtxCount */
|
||||||
{0} /* stream_builder — initialized below */
|
{0} /* stream_builder — initialized below */
|
||||||
};
|
};
|
||||||
if (flatcc_builder_init(&emulContext.stream_builder)) {
|
if (flatcc_builder_init(&emulContext.stream_builder)) {
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ typedef struct {
|
|||||||
// store copies of hierarchical path per device
|
// store copies of hierarchical path per device
|
||||||
char** paths[MAX_DEVICES]; // each is a NULL-terminated string array
|
char** paths[MAX_DEVICES]; // each is a NULL-terminated string array
|
||||||
size_t path_lens[MAX_DEVICES]; // number of components per path
|
size_t path_lens[MAX_DEVICES]; // number of components per path
|
||||||
|
size_t seg_counts[MAX_DEVICES]; // number of memory segments per device
|
||||||
size_t count;
|
size_t count;
|
||||||
} LoadState;
|
} LoadState;
|
||||||
|
|
||||||
@@ -137,6 +138,12 @@ static int load_devices_recursive(
|
|||||||
size_t idx = st->count;
|
size_t idx = st->count;
|
||||||
st->handles[idx] = dev;
|
st->handles[idx] = dev;
|
||||||
|
|
||||||
|
// Store segment count from FlatBuffer config
|
||||||
|
hmmmm_config_MemSegment_vec_t dev_segs =
|
||||||
|
hmmmm_config_BaseDeviceConfig_mem_segments(base);
|
||||||
|
st->seg_counts[idx] = dev_segs
|
||||||
|
? hmmmm_config_MemSegment_vec_len(dev_segs) : 0;
|
||||||
|
|
||||||
// Copy path
|
// Copy path
|
||||||
st->path_lens[idx] = st->depth;
|
st->path_lens[idx] = st->depth;
|
||||||
st->paths[idx] = calloc(st->depth + 1, sizeof(char*));
|
st->paths[idx] = calloc(st->depth + 1, sizeof(char*));
|
||||||
@@ -183,10 +190,276 @@ static void free_load_state_paths(LoadState* st)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Find a device index by its leaf ID (last path component)
|
||||||
|
static size_t find_device_by_id(LoadState* st, const char* id)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < st->count; i++) {
|
||||||
|
// Match by last path component (the device's own ID)
|
||||||
|
const char* leaf = st->paths[i][st->path_lens[i] - 1];
|
||||||
|
if (strcmp(leaf, id) == 0) return i;
|
||||||
|
}
|
||||||
|
return (size_t)~0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Find a segment index by name in a device
|
||||||
|
static size_t find_seg_by_name(device_handle_t* dev, size_t seg_count, const char* name)
|
||||||
|
{
|
||||||
|
device_mem_t* mem = dev->ctx->deviceMem;
|
||||||
|
for (size_t i = 0; i < seg_count; i++) {
|
||||||
|
if (strcmp(mem->memsegNames[i], name) == 0) return i;
|
||||||
|
}
|
||||||
|
return (size_t)~0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int apply_projections(
|
||||||
|
hmmmm_config_ComposeDeviceConfig_table_t compose,
|
||||||
|
LoadState* st,
|
||||||
|
char* errbuf)
|
||||||
|
{
|
||||||
|
hmmmm_config_Projection_vec_t proj_vec =
|
||||||
|
hmmmm_config_ComposeDeviceConfig_projections(compose);
|
||||||
|
size_t proj_n = proj_vec ? hmmmm_config_Projection_vec_len(proj_vec) : 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < proj_n; i++) {
|
||||||
|
hmmmm_config_Projection_table_t proj =
|
||||||
|
hmmmm_config_Projection_vec_at(proj_vec, i);
|
||||||
|
|
||||||
|
flatbuffers_string_t base_at = hmmmm_config_Projection_base_at(proj);
|
||||||
|
flatbuffers_string_t base_seg = hmmmm_config_Projection_base_seg(proj);
|
||||||
|
flatbuffers_string_t target_at = hmmmm_config_Projection_target_at(proj);
|
||||||
|
flatbuffers_string_t target_seg = hmmmm_config_Projection_target_seg(proj);
|
||||||
|
uint32_t shift = hmmmm_config_Projection_shift(proj);
|
||||||
|
|
||||||
|
if (!base_at || !base_seg || !target_at || !target_seg) {
|
||||||
|
sprintf(errbuf, "projection %zu: missing field", i);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t base_idx = find_device_by_id(st, base_at);
|
||||||
|
if (base_idx == (size_t)~0) {
|
||||||
|
sprintf(errbuf, "projection %zu: base device '%s' not found", i, base_at);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t target_idx = find_device_by_id(st, target_at);
|
||||||
|
if (target_idx == (size_t)~0) {
|
||||||
|
sprintf(errbuf, "projection %zu: target device '%s' not found", i, target_at);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t base_seg_idx = find_seg_by_name(
|
||||||
|
st->handles[base_idx], st->seg_counts[base_idx], base_seg);
|
||||||
|
if (base_seg_idx == (size_t)~0) {
|
||||||
|
sprintf(errbuf, "projection %zu: base segment '%s' not found in '%s'",
|
||||||
|
i, base_seg, base_at);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t target_seg_idx = find_seg_by_name(
|
||||||
|
st->handles[target_idx], st->seg_counts[target_idx], target_seg);
|
||||||
|
if (target_seg_idx == (size_t)~0) {
|
||||||
|
sprintf(errbuf, "projection %zu: target segment '%s' not found in '%s'",
|
||||||
|
i, target_seg, target_at);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remap: target device's segment now points to base device's segment memory + shift
|
||||||
|
void* base_ptr = st->handles[base_idx]->ctx->deviceMem->cells[base_seg_idx];
|
||||||
|
st->handles[target_idx]->ctx->deviceMem->cells[target_seg_idx] =
|
||||||
|
(uint8_t*)base_ptr + shift;
|
||||||
|
|
||||||
|
printf("[CTRL/CONFIG] projection: %s.%s -> %s.%s (shift=%u)\n",
|
||||||
|
base_at, base_seg, target_at, target_seg, shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ── Intercept handler context and functions ─────────────────────────────────
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t* point_cell; // direct pointer to point device's cell
|
||||||
|
uint8_t* base_cell; // direct pointer to base device's cell (shadow_copy)
|
||||||
|
uint8_t word_len;
|
||||||
|
} intercept_ctx_t;
|
||||||
|
|
||||||
|
// shadow_replace: read from point device instead of base
|
||||||
|
static void* intercept_replace_read(uint64_t ident, uint64_t addr, void* rawCells)
|
||||||
|
{
|
||||||
|
intercept_ctx_t* ctx = (intercept_ctx_t*)(uintptr_t)ident;
|
||||||
|
return ctx->point_cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
// shadow_replace: write to point device instead of base
|
||||||
|
static void intercept_replace_write(uint64_t ident, uint64_t addr, void* rawCells, void* data)
|
||||||
|
{
|
||||||
|
intercept_ctx_t* ctx = (intercept_ctx_t*)(uintptr_t)ident;
|
||||||
|
memcpy(ctx->point_cell, data, ctx->word_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// shadow_copy: write to both base and point
|
||||||
|
static void intercept_copy_write(uint64_t ident, uint64_t addr, void* rawCells, void* data)
|
||||||
|
{
|
||||||
|
intercept_ctx_t* ctx = (intercept_ctx_t*)(uintptr_t)ident;
|
||||||
|
memcpy(ctx->base_cell, data, ctx->word_len);
|
||||||
|
memcpy(ctx->point_cell, data, ctx->word_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_INTERCEPTS 256
|
||||||
|
|
||||||
|
static int apply_intercepts(
|
||||||
|
hmmmm_config_ComposeDeviceConfig_table_t compose,
|
||||||
|
LoadState* st,
|
||||||
|
intercept_ctx_t** out_ctxs,
|
||||||
|
size_t* out_ctx_count,
|
||||||
|
char* errbuf)
|
||||||
|
{
|
||||||
|
hmmmm_config_Intercept_vec_t icpt_vec =
|
||||||
|
hmmmm_config_ComposeDeviceConfig_intercepts(compose);
|
||||||
|
size_t icpt_n = icpt_vec ? hmmmm_config_Intercept_vec_len(icpt_vec) : 0;
|
||||||
|
|
||||||
|
*out_ctx_count = 0;
|
||||||
|
if (icpt_n == 0) { *out_ctxs = NULL; return 0; }
|
||||||
|
if (icpt_n > MAX_INTERCEPTS) {
|
||||||
|
sprintf(errbuf, "too many intercepts (%zu)", icpt_n);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate array of intercept contexts (one per intercept)
|
||||||
|
intercept_ctx_t* ctxs = calloc(icpt_n, sizeof(intercept_ctx_t));
|
||||||
|
if (!ctxs) { sprintf(errbuf, "alloc intercept contexts"); return -1; }
|
||||||
|
|
||||||
|
for (size_t i = 0; i < icpt_n; i++) {
|
||||||
|
hmmmm_config_Intercept_table_t icpt =
|
||||||
|
hmmmm_config_Intercept_vec_at(icpt_vec, i);
|
||||||
|
|
||||||
|
flatbuffers_string_t name = hmmmm_config_Intercept_name(icpt);
|
||||||
|
int8_t op = hmmmm_config_Intercept_op(icpt);
|
||||||
|
int8_t mode = hmmmm_config_Intercept_mode(icpt);
|
||||||
|
|
||||||
|
flatbuffers_string_t base_at = hmmmm_config_Intercept_base_at(icpt);
|
||||||
|
flatbuffers_string_t base_seg = hmmmm_config_Intercept_base_seg(icpt);
|
||||||
|
uint32_t base_addr = hmmmm_config_Intercept_base_addr(icpt);
|
||||||
|
|
||||||
|
flatbuffers_string_t point_at = hmmmm_config_Intercept_point_at(icpt);
|
||||||
|
flatbuffers_string_t point_seg = hmmmm_config_Intercept_point_seg(icpt);
|
||||||
|
uint32_t point_addr = hmmmm_config_Intercept_point_addr(icpt);
|
||||||
|
|
||||||
|
if (!base_at || !base_seg || !point_at || !point_seg) {
|
||||||
|
sprintf(errbuf, "intercept %zu: missing field", i);
|
||||||
|
free(ctxs);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve base device + segment
|
||||||
|
size_t base_idx = find_device_by_id(st, base_at);
|
||||||
|
if (base_idx == (size_t)~0) {
|
||||||
|
sprintf(errbuf, "intercept %zu: base device '%s' not found", i, base_at);
|
||||||
|
free(ctxs); return -1;
|
||||||
|
}
|
||||||
|
size_t base_seg_idx = find_seg_by_name(
|
||||||
|
st->handles[base_idx], st->seg_counts[base_idx], base_seg);
|
||||||
|
if (base_seg_idx == (size_t)~0) {
|
||||||
|
sprintf(errbuf, "intercept %zu: base segment '%s' not found in '%s'",
|
||||||
|
i, base_seg, base_at);
|
||||||
|
free(ctxs); return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve point device + segment
|
||||||
|
size_t point_idx = find_device_by_id(st, point_at);
|
||||||
|
if (point_idx == (size_t)~0) {
|
||||||
|
sprintf(errbuf, "intercept %zu: point device '%s' not found", i, point_at);
|
||||||
|
free(ctxs); return -1;
|
||||||
|
}
|
||||||
|
size_t point_seg_idx = find_seg_by_name(
|
||||||
|
st->handles[point_idx], st->seg_counts[point_idx], point_seg);
|
||||||
|
if (point_seg_idx == (size_t)~0) {
|
||||||
|
sprintf(errbuf, "intercept %zu: point segment '%s' not found in '%s'",
|
||||||
|
i, point_seg, point_at);
|
||||||
|
free(ctxs); return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
device_mem_t* base_mem = st->handles[base_idx]->ctx->deviceMem;
|
||||||
|
device_mem_t* point_mem = st->handles[point_idx]->ctx->deviceMem;
|
||||||
|
|
||||||
|
// Compute global address on base device (for handler array index)
|
||||||
|
uint64_t base_global = base_mem->memsegShifts[base_seg_idx] + base_addr;
|
||||||
|
|
||||||
|
// Get word length from base segment
|
||||||
|
uint8_t wl = 1; // default
|
||||||
|
// memsegShifts difference gives segment size; use rawCells layout
|
||||||
|
// We can get wordLen from the point segment shift or use 1 for byte-addressable
|
||||||
|
|
||||||
|
// Fill intercept context
|
||||||
|
intercept_ctx_t* ctx = &ctxs[i];
|
||||||
|
ctx->word_len = wl;
|
||||||
|
ctx->base_cell = (uint8_t*)base_mem->rawCells + base_global;
|
||||||
|
ctx->point_cell = (uint8_t*)point_mem->rawCells
|
||||||
|
+ point_mem->memsegShifts[point_seg_idx] + point_addr;
|
||||||
|
|
||||||
|
uint64_t ident = (uint64_t)(uintptr_t)ctx;
|
||||||
|
|
||||||
|
// NOTE: WRITE_MEM macro reads ident from smartAddrReadHandlers, not
|
||||||
|
// smartAddrWriteHandlers. Always set ident on both arrays so that
|
||||||
|
// write handlers receive the correct context pointer.
|
||||||
|
base_mem->smartAddrReadHandlers[base_global].ident = ident;
|
||||||
|
base_mem->smartAddrWriteHandlers[base_global].ident = ident;
|
||||||
|
|
||||||
|
if (mode == hmmmm_config_InterceptMode_shadow_replace) {
|
||||||
|
// Replace: redirect read and/or write
|
||||||
|
if (op == hmmmm_config_InterceptOp_op_read ||
|
||||||
|
op == hmmmm_config_InterceptOp_op_both) {
|
||||||
|
base_mem->smartAddrReadHandlers[base_global].func = intercept_replace_read;
|
||||||
|
}
|
||||||
|
if (op == hmmmm_config_InterceptOp_op_write ||
|
||||||
|
op == hmmmm_config_InterceptOp_op_both) {
|
||||||
|
base_mem->smartAddrWriteHandlers[base_global].func = intercept_replace_write;
|
||||||
|
}
|
||||||
|
} else if (mode == hmmmm_config_InterceptMode_shadow_copy) {
|
||||||
|
// Copy: only affects writes (read stays at base)
|
||||||
|
if (op == hmmmm_config_InterceptOp_op_write ||
|
||||||
|
op == hmmmm_config_InterceptOp_op_both) {
|
||||||
|
base_mem->smartAddrWriteHandlers[base_global].func = intercept_copy_write;
|
||||||
|
}
|
||||||
|
} else if (mode == hmmmm_config_InterceptMode_callback) {
|
||||||
|
// Callback mode: not implemented yet — skip with warning
|
||||||
|
printf("[CTRL/CONFIG] intercept %zu '%s': callback mode not yet implemented\n",
|
||||||
|
i, name ? name : "(unnamed)");
|
||||||
|
} else {
|
||||||
|
sprintf(errbuf, "intercept %zu: unknown mode %d", i, mode);
|
||||||
|
free(ctxs); return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("[CTRL/CONFIG] intercept: %s.%s[%u] -> %s.%s[%u] mode=%s op=%s\n",
|
||||||
|
base_at, base_seg, base_addr,
|
||||||
|
point_at, point_seg, point_addr,
|
||||||
|
hmmmm_config_InterceptMode_name(mode),
|
||||||
|
hmmmm_config_InterceptOp_name(op));
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_ctxs = ctxs;
|
||||||
|
*out_ctx_count = icpt_n;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void free_old_config(EmulContext* emulContext)
|
static void free_old_config(EmulContext* emulContext)
|
||||||
{
|
{
|
||||||
if (emulContext->devicesCount == 0) return;
|
if (emulContext->devicesCount == 0) return;
|
||||||
|
|
||||||
|
// Free intercept contexts
|
||||||
|
if (emulContext->interceptCtxs) {
|
||||||
|
for (size_t i = 0; i < emulContext->interceptCtxCount; i++) {
|
||||||
|
free(emulContext->interceptCtxs[i]);
|
||||||
|
}
|
||||||
|
free(emulContext->interceptCtxs);
|
||||||
|
emulContext->interceptCtxs = NULL;
|
||||||
|
emulContext->interceptCtxCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < emulContext->devicesCount; i++) {
|
for (size_t i = 0; i < emulContext->devicesCount; i++) {
|
||||||
device_handle_t* dev = (device_handle_t*)emulContext->deviceHandles[i];
|
device_handle_t* dev = (device_handle_t*)emulContext->deviceHandles[i];
|
||||||
closeBaseDevice(dev);
|
closeBaseDevice(dev);
|
||||||
@@ -284,6 +557,50 @@ void handleConfigCtrlMessage(
|
|||||||
|
|
||||||
printf("[CTRL/CONFIG] loaded %zu devices\n", st.count);
|
printf("[CTRL/CONFIG] loaded %zu devices\n", st.count);
|
||||||
|
|
||||||
|
// Apply projections
|
||||||
|
if (apply_projections(root, &st, errbuf) != 0) {
|
||||||
|
printf("[CTRL/CONFIG] projection error: %s\n", errbuf);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < st.count; i++) {
|
||||||
|
closeBaseDevice(st.handles[i]);
|
||||||
|
free(st.handles[i]);
|
||||||
|
}
|
||||||
|
free_load_state_paths(&st);
|
||||||
|
|
||||||
|
size_t msg_len;
|
||||||
|
uint8_t* out = fb_build_config_error(nonce, errbuf, &msg_len);
|
||||||
|
dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, out, msg_len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply intercepts
|
||||||
|
intercept_ctx_t* icpt_ctxs = NULL;
|
||||||
|
size_t icpt_count = 0;
|
||||||
|
if (apply_intercepts(root, &st, &icpt_ctxs, &icpt_count, errbuf) != 0) {
|
||||||
|
printf("[CTRL/CONFIG] intercept error: %s\n", errbuf);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < st.count; i++) {
|
||||||
|
closeBaseDevice(st.handles[i]);
|
||||||
|
free(st.handles[i]);
|
||||||
|
}
|
||||||
|
free_load_state_paths(&st);
|
||||||
|
|
||||||
|
size_t msg_len;
|
||||||
|
uint8_t* out = fb_build_config_error(nonce, errbuf, &msg_len);
|
||||||
|
dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, out, msg_len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store intercept contexts for later cleanup
|
||||||
|
if (icpt_ctxs) {
|
||||||
|
emulContext->interceptCtxs = calloc(1, sizeof(void*));
|
||||||
|
emulContext->interceptCtxs[0] = icpt_ctxs;
|
||||||
|
emulContext->interceptCtxCount = 1;
|
||||||
|
} else {
|
||||||
|
emulContext->interceptCtxs = NULL;
|
||||||
|
emulContext->interceptCtxCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Allocate new arrays for EmulContext
|
// Allocate new arrays for EmulContext
|
||||||
size_t dc = st.count;
|
size_t dc = st.count;
|
||||||
emulContext->devicesCount = dc;
|
emulContext->devicesCount = dc;
|
||||||
|
|||||||
Reference in New Issue
Block a user