copapy/src/coparun/runmem.c

199 lines
7.1 KiB
C
Raw Normal View History

2025-09-20 21:25:07 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
2025-10-18 21:26:35 +00:00
#include <math.h>
#include "runmem.h"
2025-10-04 20:57:45 +00:00
#include "mem_man.h"
2025-09-20 21:25:07 +00:00
#ifdef ENABLE_LOGGING
#define LOG(...) printf(__VA_ARGS__)
#define BLOG(...) printf(__VA_ARGS__)
#elif ENABLE_BASIC_LOGGING
#define LOG(...)
#define BLOG(...) printf(__VA_ARGS__)
#else
#define LOG(...)
#define BLOG(...)
#endif
2025-10-04 20:57:45 +00:00
/* Globals declared extern in runmem.h */
uint8_t *data_memory = NULL;
uint32_t data_memory_len = 0;
uint8_t *executable_memory = NULL;
uint32_t executable_memory_len = 0;
entry_point_t entr_point = NULL;
2025-10-05 21:10:38 +00:00
int data_offs = 0;
2025-09-20 21:25:07 +00:00
void patch(uint8_t *patch_addr, uint32_t patch_mask, int32_t value) {
2025-10-29 21:29:15 +00:00
uint32_t *val_ptr = (uint32_t*)patch_addr;
uint32_t original = *val_ptr;
int32_t shift_factor = patch_mask & -patch_mask;
uint32_t new_value = (original & ~patch_mask) | ((uint32_t)(value * shift_factor) & patch_mask);
2025-10-29 21:29:15 +00:00
*val_ptr = new_value;
}
void patch_hi21(uint8_t *patch_addr, int32_t page_offset) {
uint32_t instr = *(uint32_t *)patch_addr;
// Split page_offset into immhi (upper 19 bits) and immlo (lower 2 bits)
uint32_t immlo = page_offset & 0x3; // bits[1:0]
uint32_t immhi = (page_offset >> 2) & 0x7FFFF; // bits[20:2]
// Clear previous imm fields: immhi (bits[23:5]) and immlo (bits[30:29])
instr &= ~((0x7FFFFu << 5) | (0x3 << 29));
// Set new immhi and immlo
instr |= (immhi << 5) | (immlo << 29);
*(uint32_t *)patch_addr = instr;
}
2025-10-04 20:57:45 +00:00
void free_memory() {
deallocate_memory(executable_memory, executable_memory_len);
deallocate_memory(data_memory, data_memory_len);
executable_memory_len = 0;
2025-10-04 20:57:45 +00:00
data_memory_len = 0;
}
2025-09-20 21:25:07 +00:00
2025-10-05 21:10:38 +00:00
int update_data_offs() {
if (data_memory && executable_memory && (data_memory - executable_memory > 0x7FFFFFFF || executable_memory - data_memory > 0x7FFFFFFF)) {
perror("Error: code and data memory to far apart");
return 0;
}
2025-10-05 21:10:38 +00:00
if (data_memory && executable_memory && (data_memory - executable_memory > 0x7FFFFFFF || executable_memory - data_memory > 0x7FFFFFFF)) {
perror("Error: code and data memory to far apart");
return 0;
}
2025-10-05 21:10:00 +00:00
data_offs = (int)(data_memory - executable_memory);
2025-10-05 21:10:38 +00:00
return 1;
}
int floor_div(int a, int b) {
return a / b - ((a % b != 0) && ((a < 0) != (b < 0)));
}
2025-10-04 20:57:45 +00:00
int parse_commands(uint8_t *bytes) {
2025-09-20 21:25:07 +00:00
int32_t value;
uint32_t command;
2025-10-29 21:29:15 +00:00
uint32_t patch_mask;
int32_t patch_scale;
2025-09-20 21:25:07 +00:00
uint32_t offs;
uint32_t size;
2025-10-07 20:56:04 +00:00
int end_flag = 0;
2025-10-12 21:22:58 +00:00
uint32_t rel_entr_point = 0;
2025-09-20 21:25:07 +00:00
2025-10-07 20:56:04 +00:00
while(!end_flag) {
2025-09-20 21:25:07 +00:00
command = *(uint32_t*)bytes;
bytes += 4;
switch(command) {
2025-10-05 21:10:38 +00:00
case ALLOCATE_DATA:
2025-09-20 21:25:07 +00:00
size = *(uint32_t*)bytes; bytes += 4;
2025-10-04 20:57:45 +00:00
data_memory = allocate_data_memory(size);
data_memory_len = size;
LOG("ALLOCATE_DATA size=%i mem_addr=%p\n", size, (void*)data_memory);
2025-10-07 20:56:04 +00:00
if (!update_data_offs()) end_flag = -4;
2025-09-20 21:25:07 +00:00
break;
2025-10-05 21:10:38 +00:00
case COPY_DATA:
2025-09-20 21:25:07 +00:00
offs = *(uint32_t*)bytes; bytes += 4;
size = *(uint32_t*)bytes; bytes += 4;
LOG("COPY_DATA offs=%i size=%i\n", offs, size);
2025-09-20 21:25:07 +00:00
memcpy(data_memory + offs, bytes, size); bytes += size;
break;
2025-10-05 21:10:38 +00:00
case ALLOCATE_CODE:
2025-09-20 21:25:07 +00:00
size = *(uint32_t*)bytes; bytes += 4;
2025-10-04 20:57:45 +00:00
executable_memory = allocate_executable_memory(size);
2025-09-20 21:25:07 +00:00
executable_memory_len = size;
LOG("ALLOCATE_CODE size=%i mem_addr=%p\n", size, (void*)executable_memory);
//LOG("# d %i c %i off %i\n", data_memory, executable_memory, data_offs);
2025-10-07 20:56:04 +00:00
if (!update_data_offs()) end_flag = -4;
2025-09-20 21:25:07 +00:00
break;
case COPY_CODE:
offs = *(uint32_t*)bytes; bytes += 4;
size = *(uint32_t*)bytes; bytes += 4;
LOG("COPY_CODE offs=%i size=%i\n", offs, size);
2025-09-20 21:25:07 +00:00
memcpy(executable_memory + offs, bytes, size); bytes += size;
break;
2025-09-21 21:08:30 +00:00
case PATCH_FUNC:
2025-09-20 21:25:07 +00:00
offs = *(uint32_t*)bytes; bytes += 4;
2025-10-29 21:29:15 +00:00
patch_mask = *(uint32_t*)bytes; bytes += 4;
patch_scale = *(int32_t*)bytes; bytes += 4;
2025-09-20 21:25:07 +00:00
value = *(int32_t*)bytes; bytes += 4;
LOG("PATCH_FUNC patch_offs=%i patch_mask=%#08x scale=%i value=%i\n",
offs, patch_mask, patch_scale, value);
patch(executable_memory + offs, patch_mask, value / patch_scale);
2025-09-20 21:25:07 +00:00
break;
2025-09-21 21:08:30 +00:00
case PATCH_OBJECT:
2025-09-20 21:25:07 +00:00
offs = *(uint32_t*)bytes; bytes += 4;
2025-10-29 21:29:15 +00:00
patch_mask = *(uint32_t*)bytes; bytes += 4;
patch_scale = *(int32_t*)bytes; bytes += 4;
2025-09-20 21:25:07 +00:00
value = *(int32_t*)bytes; bytes += 4;
LOG("PATCH_OBJECT patch_offs=%i patch_mask=%#08x scale=%i value=%i\n",
offs, patch_mask, patch_scale, value);
patch(executable_memory + offs, patch_mask, value / patch_scale + data_offs / patch_scale);
2025-09-20 21:25:07 +00:00
break;
2025-10-12 21:21:34 +00:00
case PATCH_OBJECT_HI21:
offs = *(uint32_t*)bytes; bytes += 4;
patch_mask = *(uint32_t*)bytes; bytes += 4;
patch_scale = *(int32_t*)bytes; bytes += 4;
value = *(int32_t*)bytes; bytes += 4;
LOG("PATCH_OBJECT_HI21 patch_offs=%i patch_mask=%#08x scale=%i value=%i res_value=%i\n",
offs, patch_mask, patch_scale, value, floor_div(data_offs + value, patch_scale) - (int32_t)offs / patch_scale);
patch_hi21(executable_memory + offs, floor_div(data_offs + value, patch_scale) - (int32_t)offs / patch_scale);
2025-10-18 21:26:35 +00:00
break;
2025-10-12 21:21:34 +00:00
case ENTRY_POINT:
LOG("ENTRY_POINT rel_entr_point=%i\n", rel_entr_point);
2025-09-30 21:11:14 +00:00
rel_entr_point = *(uint32_t*)bytes; bytes += 4;
2025-10-07 21:24:22 +00:00
entr_point = (entry_point_t)(executable_memory + rel_entr_point);
2025-10-04 20:57:45 +00:00
mark_mem_executable(executable_memory, executable_memory_len);
2025-10-12 21:21:34 +00:00
break;
case RUN_PROG:
LOG("RUN_PROG\n");
int ret = entr_point();
BLOG("Return value: %i\n", ret);
2025-09-20 21:25:07 +00:00
break;
case READ_DATA:
offs = *(uint32_t*)bytes; bytes += 4;
size = *(uint32_t*)bytes; bytes += 4;
BLOG("READ_DATA offs=%i size=%i data=", offs, size);
for (uint32_t i = 0; i < size; i++) {
printf("%02X ", data_memory[offs + i]);
}
printf("\n");
break;
2025-10-04 20:57:45 +00:00
case FREE_MEMORY:
LOG("FREE_MENORY\n");
2025-10-04 20:57:45 +00:00
free_memory();
break;
case DUMP_CODE:
LOG("DUMP_CODE\n");
end_flag = 2;
break;
2025-10-12 21:22:12 +00:00
case END_COM:
LOG("END_COM\n");
2025-10-07 20:56:04 +00:00
end_flag = 1;
2025-10-04 20:57:45 +00:00
break;
2025-09-20 21:25:07 +00:00
2025-10-05 21:10:38 +00:00
default:
LOG("Unknown command\n");
2025-10-07 20:56:04 +00:00
end_flag = -1;
2025-09-20 21:25:07 +00:00
break;
}
}
2025-10-07 20:56:04 +00:00
return end_flag;
2025-09-20 21:25:07 +00:00
}