command parser updated

This commit is contained in:
Nicolas 2026-03-19 15:59:27 +01:00
parent 33b833c41a
commit bd49f02dee
7 changed files with 255 additions and 159 deletions

View File

@ -6,7 +6,8 @@ ext = Extension(
"src/coparun/coparun_module.c", "src/coparun/coparun_module.c",
"src/coparun/runmem.c", "src/coparun/runmem.c",
"src/coparun/mem_man.c" "src/coparun/mem_man.c"
] ],
#define_macros=[("ENABLE_BASIC_LOGGING", None)]
) )
setup( setup(

View File

@ -64,10 +64,22 @@ int main(int argc, char *argv[]) {
targ.data_memory = NULL; targ.data_memory = NULL;
targ.entr_point = NULL; targ.entr_point = NULL;
targ.data_offs = 0; targ.data_offs = 0;
targ.rx_state = RX_STATE_IDLE;
targ.state_flag = 0;
int ret = parse_commands(&targ, file_buff); int ret = parse_commands(&targ, file_buff, (uint32_t)sz);
if (ret == 2) { /*int offs = 0;
for (int i = 0; i < sz + 1; i++) {
if (i - offs < 0) {
printf("Error: parse_commands returned invalid offset i=%i offs=%i\n", i, offs);
return EXIT_FAILURE;
}
offs += parse_commands(&targ, file_buff + offs, i - offs);
printf("> i=%i offs=%i\n", i, offs);
}*/
if (targ.state_flag == STATE_FLAG_DUMP_CODE) {
/* Dump code for debugging */ /* Dump code for debugging */
if (argc != 3) { if (argc != 3) {
fprintf(stderr, "Usage: %s <code_file> <memory_dump_file>\n", argv[0]); fprintf(stderr, "Usage: %s <code_file> <memory_dump_file>\n", argv[0]);
@ -80,5 +92,5 @@ int main(int argc, char *argv[]) {
free_memory(&targ); free_memory(&targ);
return ret < 0; return targ.state_flag < 0;
} }

View File

@ -14,7 +14,6 @@ static PyObject* coparun(PyObject* self, PyObject* args) {
PyObject *handle_obj; PyObject *handle_obj;
const char *buf; const char *buf;
Py_ssize_t buf_len; Py_ssize_t buf_len;
int result;
// Expect: handle, bytes // Expect: handle, bytes
if (!PyArg_ParseTuple(args, "Oy#", &handle_obj, &buf, &buf_len)) { if (!PyArg_ParseTuple(args, "Oy#", &handle_obj, &buf, &buf_len)) {
@ -30,10 +29,10 @@ static PyObject* coparun(PyObject* self, PyObject* args) {
/* If parse_commands may run for a long time, release the GIL. */ /* If parse_commands may run for a long time, release the GIL. */
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
result = parse_commands(context, (uint8_t*)buf); parse_commands(context, (uint8_t*)buf, (uint32_t)buf_len);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
return PyLong_FromLong(result); return PyLong_FromLong(context->state_flag);
} }
static PyObject* read_data_mem(PyObject* self, PyObject* args) { static PyObject* read_data_mem(PyObject* self, PyObject* args) {
@ -74,6 +73,7 @@ static PyObject* read_data_mem(PyObject* self, PyObject* args) {
} }
static PyObject* create_target(PyObject* self, PyObject* args) { static PyObject* create_target(PyObject* self, PyObject* args) {
// Allocate a new runmem_t struct, zero-initialized
runmem_t *context = (runmem_t*)calloc(1, sizeof(runmem_t)); runmem_t *context = (runmem_t*)calloc(1, sizeof(runmem_t));
if (!context) { if (!context) {
return PyErr_NoMemory(); return PyErr_NoMemory();

View File

@ -6,12 +6,46 @@
* handles memory management accordingly. * handles memory management accordingly.
*/ */
#include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#ifdef _WIN32
#if defined DATA_MEMORY_ADDR || defined EXECUTABLE_MEMORY_ADDR
/* Bare metal implementations */
#if not defined(EXECUTABLE_MEMORY_ADDR) || not defined(DATA_MEMORY_ADDR)
#error "For bare metal, you must define DATA_MEMORY_ADDR and DATA_EXECUTABLE_MEMORY_ADDR."
#endif
uint8_t *allocate_executable_memory(uint32_t num_bytes) {
return (uint8_t*)EXECUTABLE_MEMORY_ADDR;
}
uint8_t *allocate_data_memory(uint32_t num_bytes) {
return (uint8_t*)DATA_MEMORY_ADDR;
}
int mark_mem_executable(uint8_t *memory, uint32_t memory_len) {
/* No-op for bare metal */
return 1;
}
void deallocate_memory(uint8_t *memory, uint32_t memory_len) {
/* No-op for bare metal */
}
void memcpy(void *dest, const void *src, size_t n) {
uint8_t *d = (uint8_t*)dest;
const uint8_t *s = (const uint8_t*)src;
for (size_t i = 0; i < n; i++) {
d[i] = s[i];
}
return 0;
}
#elif defined _WIN32
#include <windows.h> #include <windows.h>
#include <string.h>
#include <stdio.h>
/* Windows implementations */ /* Windows implementations */
@ -62,6 +96,9 @@ void deallocate_memory(uint8_t *memory, uint32_t memory_len) {
#else #else
#include <sys/mman.h> #include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
/* POSIX implementations */ /* POSIX implementations */

View File

@ -7,4 +7,10 @@ uint8_t *allocate_buffer_memory(uint32_t num_bytes);
int mark_mem_executable(uint8_t *memory, uint32_t memory_len); int mark_mem_executable(uint8_t *memory, uint32_t memory_len);
void deallocate_memory(uint8_t *memory, uint32_t memory_len); void deallocate_memory(uint8_t *memory, uint32_t memory_len);
#ifdef DATA_MEMORY_ADDR
void memcpy(void *dest, const void *src, size_t n);
#else
#include <string.h>
#endif
#endif /* MEM_MAN_H */ #endif /* MEM_MAN_H */

View File

@ -5,10 +5,6 @@
* and jumps to the entry point of the copapy program * and jumps to the entry point of the copapy program
*/ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "runmem.h" #include "runmem.h"
#include "mem_man.h" #include "mem_man.h"
@ -60,7 +56,7 @@ void patch_arm32_abs(uint8_t *patch_addr, uint32_t imm16)
void patch_arm_thm_abs(uint8_t *patch_addr, uint32_t imm16) void patch_arm_thm_abs(uint8_t *patch_addr, uint32_t imm16)
{ {
// Thumb MOVW (T3) / MOVT (T1) encoding // Thumb MOVW (T3) / MOVT (T1) encoding
uint16_t *instr16 = (uint16_t *)patch_addr; uint16_t *instr16 = (uint16_t *)patch_addr;
uint16_t first_half = instr16[0]; uint16_t first_half = instr16[0];
uint16_t second_half = instr16[1]; uint16_t second_half = instr16[1];
@ -144,176 +140,213 @@ int floor_div(int a, int b) {
return a / b - ((a % b != 0) && ((a < 0) != (b < 0))); return a / b - ((a % b != 0) && ((a < 0) != (b < 0)));
} }
int parse_commands(runmem_t *context, uint8_t *bytes) { int parse_commands(runmem_t *context, uint8_t *bytes, uint32_t lengths) {
int32_t value; int32_t value;
uint32_t command; uint32_t command;
uint32_t patch_mask; uint32_t patch_mask;
int32_t patch_scale; int32_t patch_scale;
uint32_t offs; uint32_t offs;
uint32_t size; uint32_t size;
int end_flag = 0;
uint32_t rel_entr_point = 0; uint32_t rel_entr_point = 0;
uint32_t header_size;
uint8_t *byte_offset = bytes;
while(!end_flag) { while(bytes < byte_offset + lengths) {
command = *(uint32_t*)bytes; //LOG("# LOOP START: context->rx_state=%i byte_index=%i lengths=%i\n", context->rx_state, bytes - byte_offset, lengths);
bytes += 4; if (context->rx_state == RX_STATE_IDLE) {
switch(command) { uint32_t remaining_bytes = (uint32_t)(byte_offset + lengths - bytes);
case ALLOCATE_DATA: if (remaining_bytes < 4) {
size = *(uint32_t*)bytes; bytes += 4; return bytes - byte_offset; // Return the number of bytes processed
context->data_memory = allocate_data_memory(size); }
context->data_memory_len = size; command = *(uint32_t*)bytes;
LOG("ALLOCATE_DATA size=%i mem_addr=%p\n", size, (void*)context->data_memory); header_size = (command >> 16) & 0xFFFF;
if (!update_data_offs(context)) end_flag = -4; if (remaining_bytes < 4 + header_size) {
break; return bytes - byte_offset; // Return the number of bytes processed
}
//LOG("+ Switch to RX_STATE_HEADER; context->rx_state=%i byte_index=%i lengths=%i\n", context->rx_state, bytes - byte_offset, lengths);
context->rx_state = RX_STATE_HEADER;
} else if (context->rx_state == RX_STATE_DATA) {
uint32_t chunk_size = context->data_size;
if (lengths - (bytes - byte_offset) < chunk_size) {
chunk_size = lengths - (bytes - byte_offset);
}
//LOG(" -> COPY_DATA chunk_size=%i remaining_data_size=%i\n", chunk_size, context->data_size);
memcpy(context->data_dest, context->data_src, chunk_size);
context->data_dest += chunk_size;
context->data_src += chunk_size;
context->data_size -= chunk_size;
bytes += chunk_size;
if (context->data_size == 0) {
//LOG(" -> COPY_DATA completed\n");
context->rx_state = RX_STATE_IDLE;
}
} else if (context->rx_state == RX_STATE_HEADER) {
bytes += 4;
context->rx_state = RX_STATE_IDLE;
switch(command) {
case ALLOCATE_DATA:
size = *(uint32_t*)bytes; bytes += 4;
context->data_memory = allocate_data_memory(size);
context->data_memory_len = size;
LOG("ALLOCATE_DATA size=%i mem_addr=%p\n", size, (void*)context->data_memory);
if (!update_data_offs(context)) context->state_flag = STATE_FLAG_MEM_DIST;
break;
case COPY_DATA: case COPY_DATA:
offs = *(uint32_t*)bytes; bytes += 4; offs = *(uint32_t*)bytes; bytes += 4;
size = *(uint32_t*)bytes; bytes += 4; size = *(uint32_t*)bytes; bytes += 4;
LOG("COPY_DATA offs=%i size=%i\n", offs, size); LOG("COPY_DATA offs=%i size=%i\n", offs, size);
memcpy(context->data_memory + offs, bytes, size); bytes += size; context->data_src = bytes;
break; context->data_dest = context->data_memory + offs;
context->data_size = size;
context->rx_state = RX_STATE_DATA;
break;
case ALLOCATE_CODE: case ALLOCATE_CODE:
size = *(uint32_t*)bytes; bytes += 4; size = *(uint32_t*)bytes; bytes += 4;
context->executable_memory = allocate_executable_memory(size); context->executable_memory = allocate_executable_memory(size);
context->executable_memory_len = size; context->executable_memory_len = size;
LOG("ALLOCATE_CODE size=%i mem_addr=%p\n", size, (void*)context->executable_memory); LOG("ALLOCATE_CODE size=%i mem_addr=%p\n", size, (void*)context->executable_memory);
if (!update_data_offs(context)) end_flag = -4; if (!update_data_offs(context)) context->state_flag = STATE_FLAG_MEM_DIST;
break; break;
case COPY_CODE: case COPY_CODE:
offs = *(uint32_t*)bytes; bytes += 4; offs = *(uint32_t*)bytes; bytes += 4;
size = *(uint32_t*)bytes; bytes += 4; size = *(uint32_t*)bytes; bytes += 4;
LOG("COPY_CODE offs=%i size=%i\n", offs, size); LOG("COPY_CODE offs=%i size=%i\n", offs, size);
memcpy(context->executable_memory + offs, bytes, size); bytes += size; context->data_src = bytes;
break; context->data_dest = context->executable_memory + offs;
context->data_size = size;
context->rx_state = RX_STATE_DATA;
break;
case PATCH_FUNC: case PATCH_FUNC:
offs = *(uint32_t*)bytes; bytes += 4; offs = *(uint32_t*)bytes; bytes += 4;
patch_mask = *(uint32_t*)bytes; bytes += 4; patch_mask = *(uint32_t*)bytes; bytes += 4;
patch_scale = *(int32_t*)bytes; bytes += 4; patch_scale = *(int32_t*)bytes; bytes += 4;
value = *(int32_t*)bytes; bytes += 4; value = *(int32_t*)bytes; bytes += 4;
LOG("PATCH_FUNC patch_offs=%i patch_mask=%#08x scale=%i value=%i\n", LOG("PATCH_FUNC patch_offs=%i patch_mask=%#08x scale=%i value=%i\n",
offs, patch_mask, patch_scale, value); offs, patch_mask, patch_scale, value);
patch(context->executable_memory + offs, patch_mask, value / patch_scale); patch(context->executable_memory + offs, patch_mask, value / patch_scale);
break; break;
case PATCH_OBJECT: case PATCH_OBJECT:
offs = *(uint32_t*)bytes; bytes += 4; offs = *(uint32_t*)bytes; bytes += 4;
patch_mask = *(uint32_t*)bytes; bytes += 4; patch_mask = *(uint32_t*)bytes; bytes += 4;
patch_scale = *(int32_t*)bytes; bytes += 4; patch_scale = *(int32_t*)bytes; bytes += 4;
value = *(int32_t*)bytes; bytes += 4; value = *(int32_t*)bytes; bytes += 4;
LOG("PATCH_OBJECT patch_offs=%i patch_mask=%#08x scale=%i value=%i\n", LOG("PATCH_OBJECT patch_offs=%i patch_mask=%#08x scale=%i value=%i\n",
offs, patch_mask, patch_scale, value); offs, patch_mask, patch_scale, value);
patch(context->executable_memory + offs, patch_mask, value / patch_scale + context->data_offs / patch_scale); patch(context->executable_memory + offs, patch_mask, value / patch_scale + context->data_offs / patch_scale);
break; break;
case PATCH_OBJECT_ABS: case PATCH_OBJECT_ABS:
offs = *(uint32_t*)bytes; bytes += 4; offs = *(uint32_t*)bytes; bytes += 4;
patch_mask = *(uint32_t*)bytes; bytes += 4; patch_mask = *(uint32_t*)bytes; bytes += 4;
patch_scale = *(int32_t*)bytes; bytes += 4; patch_scale = *(int32_t*)bytes; bytes += 4;
value = *(int32_t*)bytes; bytes += 4; value = *(int32_t*)bytes; bytes += 4;
LOG("PATCH_OBJECT_ABS patch_offs=%i patch_mask=%#08x scale=%i value=%i\n", LOG("PATCH_OBJECT_ABS patch_offs=%i patch_mask=%#08x scale=%i value=%i\n",
offs, patch_mask, patch_scale, value); offs, patch_mask, patch_scale, value);
patch(context->executable_memory + offs, patch_mask, value / patch_scale); patch(context->executable_memory + offs, patch_mask, value / patch_scale);
break; break;
case PATCH_OBJECT_REL: case PATCH_OBJECT_REL:
offs = *(uint32_t*)bytes; bytes += 4; offs = *(uint32_t*)bytes; bytes += 4;
bytes += 4; bytes += 4;
patch_scale = *(int32_t*)bytes; bytes += 4; patch_scale = *(int32_t*)bytes; bytes += 4;
value = *(int32_t*)bytes; bytes += 4; value = *(int32_t*)bytes; bytes += 4;
LOG("PATCH_OBJECT_REL patch_offs=%i patch_addr=%p scale=%i value=%i\n", LOG("PATCH_OBJECT_REL patch_offs=%i patch_addr=%p scale=%i value=%i\n",
offs, (void*)(context->data_memory + value), patch_scale, value); offs, (void*)(context->data_memory + value), patch_scale, value);
*(void **)(context->executable_memory + offs) = context->data_memory + value; *(void **)(context->executable_memory + offs) = context->data_memory + value;
break; break;
case PATCH_OBJECT_HI21: case PATCH_OBJECT_HI21:
offs = *(uint32_t*)bytes; bytes += 4; offs = *(uint32_t*)bytes; bytes += 4;
bytes += 4; bytes += 4;
patch_scale = *(int32_t*)bytes; bytes += 4; patch_scale = *(int32_t*)bytes; bytes += 4;
value = *(int32_t*)bytes; bytes += 4; value = *(int32_t*)bytes; bytes += 4;
LOG("PATCH_OBJECT_HI21 patch_offs=%i scale=%i value=%i res_value=%i\n", LOG("PATCH_OBJECT_HI21 patch_offs=%i scale=%i value=%i res_value=%i\n",
offs, patch_scale, value, floor_div(context->data_offs + value, patch_scale) - (int32_t)offs / patch_scale); offs, patch_scale, value, floor_div(context->data_offs + value, patch_scale) - (int32_t)offs / patch_scale);
patch_hi21(context->executable_memory + offs, floor_div(context->data_offs + value, patch_scale) - (int32_t)offs / patch_scale); patch_hi21(context->executable_memory + offs, floor_div(context->data_offs + value, patch_scale) - (int32_t)offs / patch_scale);
break; break;
case PATCH_OBJECT_ARM32_ABS: case PATCH_OBJECT_ARM32_ABS:
offs = *(uint32_t*)bytes; bytes += 4; offs = *(uint32_t*)bytes; bytes += 4;
patch_mask = *(uint32_t*)bytes; bytes += 4; patch_mask = *(uint32_t*)bytes; bytes += 4;
patch_scale = *(int32_t*)bytes; bytes += 4; patch_scale = *(int32_t*)bytes; bytes += 4;
value = *(int32_t*)bytes; bytes += 4; value = *(int32_t*)bytes; bytes += 4;
LOG("PATCH_OBJECT_ARM32_ABS patch_offs=%i patch_mask=%#08x scale=%i value=%i imm16=%#04x\n", LOG("PATCH_OBJECT_ARM32_ABS patch_offs=%i patch_mask=%#08x scale=%i value=%i imm16=%#04x\n",
offs, patch_mask, patch_scale, value, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale); offs, patch_mask, patch_scale, value, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale);
patch_arm32_abs(context->executable_memory + offs, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale); patch_arm32_abs(context->executable_memory + offs, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale);
break; break;
case PATCH_FUNC_ARM32_THM: case PATCH_FUNC_ARM32_THM:
offs = *(uint32_t*)bytes; bytes += 4; offs = *(uint32_t*)bytes; bytes += 4;
patch_mask = *(uint32_t*)bytes; bytes += 4; patch_mask = *(uint32_t*)bytes; bytes += 4;
patch_scale = *(int32_t*)bytes; bytes += 4; patch_scale = *(int32_t*)bytes; bytes += 4;
value = *(int32_t*)bytes; bytes += 4; value = *(int32_t*)bytes; bytes += 4;
LOG("PATCH_FUNC_ARM32_THM patch_offs=%i patch_mask=%#08x scale=%i value=%i\n", LOG("PATCH_FUNC_ARM32_THM patch_offs=%i patch_mask=%#08x scale=%i value=%i\n",
offs, patch_mask, patch_scale, value); offs, patch_mask, patch_scale, value);
patch_arm_thm_jump24(context->executable_memory + offs, value); patch_arm_thm_jump24(context->executable_memory + offs, value);
break; break;
case PATCH_OBJECT_ARM32_ABS_THM: case PATCH_OBJECT_ARM32_ABS_THM:
offs = *(uint32_t*)bytes; bytes += 4; offs = *(uint32_t*)bytes; bytes += 4;
patch_mask = *(uint32_t*)bytes; bytes += 4; patch_mask = *(uint32_t*)bytes; bytes += 4;
patch_scale = *(int32_t*)bytes; bytes += 4; patch_scale = *(int32_t*)bytes; bytes += 4;
value = *(int32_t*)bytes; bytes += 4; value = *(int32_t*)bytes; bytes += 4;
LOG("PATCH_OBJECT_ARM32_ABS_THM patch_offs=%i patch_mask=%#08x scale=%i value=%i imm16=%#04x\n", LOG("PATCH_OBJECT_ARM32_ABS_THM patch_offs=%i patch_mask=%#08x scale=%i value=%i imm16=%#04x\n",
offs, patch_mask, patch_scale, value, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale); offs, patch_mask, patch_scale, value, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale);
patch_arm_thm_abs(context->executable_memory + offs, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale); patch_arm_thm_abs(context->executable_memory + offs, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale);
break; break;
case ENTRY_POINT: case ENTRY_POINT:
rel_entr_point = *(uint32_t*)bytes; bytes += 4; rel_entr_point = *(uint32_t*)bytes; bytes += 4;
context->entr_point = (entry_point_t)(context->executable_memory + rel_entr_point); context->entr_point = (entry_point_t)(context->executable_memory + rel_entr_point);
LOG("ENTRY_POINT rel_entr_point=%i\n", rel_entr_point); LOG("ENTRY_POINT rel_entr_point=%i\n", rel_entr_point);
mark_mem_executable(context->executable_memory, context->executable_memory_len); mark_mem_executable(context->executable_memory, context->executable_memory_len);
break; break;
case RUN_PROG: case RUN_PROG:
LOG("RUN_PROG\n"); LOG("RUN_PROG\n");
{ {
int ret = context->entr_point(); int ret = context->entr_point();
(void)ret; (void)ret;
BLOG("Return value: %i\n", ret); BLOG("Return value: %i\n", ret);
} }
break; break;
case READ_DATA: case READ_DATA:
offs = *(uint32_t*)bytes; bytes += 4; offs = *(uint32_t*)bytes; bytes += 4;
size = *(uint32_t*)bytes; bytes += 4; size = *(uint32_t*)bytes; bytes += 4;
BLOG("READ_DATA offs=%i size=%i data=", offs, size); BLOG("READ_DATA offs=%i size=%i data=", offs, size);
for (uint32_t i = 0; i < size; i++) { for (uint32_t i = 0; i < size; i++) {
printf("%02X ", context->data_memory[offs + i]); PRINTF("%02X ", context->data_memory[offs + i]);
} }
printf("\n"); PRINTF("\n");
break; break;
case FREE_MEMORY: case FREE_MEMORY:
LOG("FREE_MENORY\n"); LOG("FREE_MENORY\n");
free_memory(context); free_memory(context);
break; break;
case DUMP_CODE: case DUMP_CODE:
LOG("DUMP_CODE\n"); LOG("DUMP_CODE\n");
end_flag = 2; context->state_flag = STATE_FLAG_DUMP_CODE;
break; break;
case END_COM: case END_COM:
LOG("END_COM\n"); LOG("END_COM\n");
end_flag = 1; context->state_flag = STATE_FLAG_END_COM;
break; break;
default: default:
LOG("Unknown command\n"); LOG("Unknown command\n");
end_flag = -1; context->state_flag = STATE_FLAG_UNKNOWN_COMMAND;
break; break;
}
} }
} }
return end_flag; return bytes - byte_offset;
} }

View File

@ -10,6 +10,13 @@
#include <stdint.h> #include <stdint.h>
#ifdef DATA_MEMORY_ADDR
#define PRINTF(...)
#else
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#endif
#ifdef ENABLE_LOGGING #ifdef ENABLE_LOGGING
#define LOG(...) printf(__VA_ARGS__) #define LOG(...) printf(__VA_ARGS__)
#define BLOG(...) printf(__VA_ARGS__) #define BLOG(...) printf(__VA_ARGS__)