diff --git a/src/copapy/_binwrite.py b/src/copapy/_binwrite.py index 27147bc..ff77918 100644 --- a/src/copapy/_binwrite.py +++ b/src/copapy/_binwrite.py @@ -10,6 +10,7 @@ Command = Enum('Command', [('ALLOCATE_DATA', 1), ('COPY_DATA', 2), ('PATCH_OBJECT_HI21', 0x2001), ('PATCH_OBJECT_ABS', 0x2002), ('PATCH_OBJECT_REL', 0x2003), + ('PATCH_OBJECT_ARM32_ABS', 0x2004), ('ENTRY_POINT', 7), ('RUN_PROG', 64), ('READ_DATA', 65), ('END_COM', 256), ('FREE_MEMORY', 257), ('DUMP_CODE', 258)]) diff --git a/src/coparun/runmem.c b/src/coparun/runmem.c index 1def456..b0ddbd3 100644 --- a/src/coparun/runmem.c +++ b/src/coparun/runmem.c @@ -40,6 +40,30 @@ void patch_hi21(uint8_t *patch_addr, int32_t page_offset) { *(uint32_t *)patch_addr = instr; } +void patch_arm32_abs(uint8_t *patch_addr, uint32_t imm16) +{ + uint32_t i = (imm16 >> 11) & 0x1; + uint32_t imm4 = (imm16 >> 12) & 0xF; + uint32_t imm3 = (imm16 >> 8) & 0x7; + uint32_t imm8 = imm16 & 0xFF; + + uint32_t instr = *((uint32_t *)patch_addr); + + // Clear the fields we are going to replace: + // imm4 → bits 19:16 + // imm3 → bits 14:12 + // i → bit 26 + // imm8 → bits 7:0 + instr &= ~(uint32_t)((0xF << 16) | (0x7 << 12) | (1 << 26) | 0xFF); + + instr |= (imm4 << 16); + instr |= (imm3 << 12); + instr |= (i << 26); + instr |= (imm8); + + *((uint32_t *)patch_addr) = instr; +} + void free_memory() { deallocate_memory(executable_memory, executable_memory_len); deallocate_memory(data_memory, data_memory_len); @@ -141,7 +165,7 @@ int parse_commands(uint8_t *bytes) { case PATCH_OBJECT_REL: offs = *(uint32_t*)bytes; bytes += 4; - patch_mask = *(uint32_t*)bytes; bytes += 4; + bytes += 4; patch_scale = *(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", @@ -150,13 +174,23 @@ int parse_commands(uint8_t *bytes) { break; case PATCH_OBJECT_HI21: + offs = *(uint32_t*)bytes; bytes += 4; + bytes += 4; + patch_scale = *(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", + offs, 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); + break; + + case PATCH_OBJECT_ARM32_ABS: 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); + LOG("PATCH_OBJECT_MOVW_ABS patch_offs=%i value=%i\n", + offs, value); + patch_arm32_abs(executable_memory + offs, (uint32_t)((uintptr_t)(data_memory + value) & patch_mask) / (uint32_t)patch_scale); break; case ENTRY_POINT: diff --git a/src/coparun/runmem.h b/src/coparun/runmem.h index 983d0f0..7f11dde 100644 --- a/src/coparun/runmem.h +++ b/src/coparun/runmem.h @@ -24,6 +24,7 @@ #define PATCH_OBJECT_HI21 0x2001 #define PATCH_OBJECT_ABS 0x2002 #define PATCH_OBJECT_REL 0x2003 +#define PATCH_OBJECT_ARM32_ABS 0x2004 #define ENTRY_POINT 7 #define RUN_PROG 64 #define READ_DATA 65