Created
February 11, 2023 14:46
-
-
Save gabonator/22e2bee8f1b1e582a912029a818dec0d to your computer and use it in GitHub Desktop.
Novation mini mk3 hack - image editor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <stdbool.h> | |
#include <string.h> | |
extern "C" uint32_t LED_BUFFER[]; | |
extern "C" uint8_t MODE; | |
extern "C" int32_t TICKMS; | |
enum {Width = 32}; | |
uint32_t image[Width][8] = {0}; | |
uint32_t color = 0xab00cd; | |
uint8_t prevMode; | |
int scroll; | |
int scrollTarget; | |
int32_t scrollLast{0}; | |
const static uint32_t palette[] = { | |
0x000000, 0xff0000, 0x00ff00, 0x0000ff, | |
0xffff00, 0xff00ff, 0x00ffff, 0xffffff}; | |
uint32_t& pixel(int x, int y) | |
{ | |
uint8_t f = (y+1)*10 + x+1; | |
return LED_BUFFER[f]; | |
} | |
extern "C" void old_updateScreen(); | |
extern "C" void new_updateScreen() | |
{ | |
if (MODE != 5) | |
old_updateScreen(); | |
} | |
extern "C" void old_loop(); | |
extern "C" void new_loop() | |
{ | |
old_loop(); | |
if (MODE != 5) | |
{ | |
prevMode = MODE; | |
return; | |
} | |
if (prevMode != 5) | |
{ | |
prevMode = MODE; | |
for (int y=0; y<8; y++) | |
for (int x=0; x<8; x++) | |
pixel(x, y) = image[x+scroll][y]; | |
for (int y=0; y<8; y++) | |
pixel(8, y) = palette[y]; | |
pixel(2, -1) = 0x404040; | |
pixel(3, -1) = 0x404040; | |
} | |
if (scroll != scrollTarget) | |
{ | |
if (scrollLast == 0) | |
scrollLast = TICKMS; | |
int passed = TICKMS - scrollLast; | |
if (passed > 50) | |
{ | |
scrollLast = TICKMS; | |
if (scrollTarget > scroll) | |
scroll++; | |
if (scrollTarget < scroll) | |
scroll--; | |
for (int y=0; y<8; y++) | |
for (int x=0; x<8; x++) | |
pixel(x, y) = image[x+scroll][y]; | |
} | |
} | |
} | |
extern "C" void old_onKeyDown(int, int); | |
extern "C" void new_onKeyDown(int a, int b) | |
{ | |
// top buttons: 1 2 3 4 5 | |
// right buttons: 19 29 39..89 | |
old_onKeyDown(a, b); | |
if (MODE != 5) | |
return; | |
if (a == 3 && scrollTarget > 0) | |
scrollTarget -= 8; | |
if (a == 4 && scrollTarget < Width-8) | |
scrollTarget += 8; | |
if ((a%10) == 9 && a >= 19 && a <= 89) | |
color = palette[(a-19)/10]; | |
int x = a%10; | |
int y = a/10; | |
if (x>=1 && x<=8 && y >= 1 && y <= 8) | |
{ | |
x--; | |
y--; | |
if (pixel(x, y) == color) | |
image[x+scroll][y] = 0; | |
else | |
image[x+scroll][y] = color; | |
pixel(x, y) = image[x+scroll][y]; | |
} | |
} | |
extern unsigned long _sidata; | |
extern unsigned long _sdata; | |
extern unsigned long _edata; | |
extern unsigned long _sbss; | |
extern unsigned long _ebss; | |
extern "C" void old_startup(); | |
extern "C" void new_startup() | |
{ | |
unsigned long *src, *dst; | |
src = &_sidata; | |
dst = &_sdata; | |
if (src != dst) | |
while(dst < &_edata) | |
*(dst++) = *(src++); | |
dst = &_sbss; | |
while(dst < &_ebss) | |
*(dst++) = 0; | |
old_startup(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
MEMORY | |
{ | |
rom (rx) : ORIGIN = 0x0801C4B0, LENGTH = 4K | |
ram (rwx) : ORIGIN = 0x2000d000, LENGTH = 2K | |
} | |
SECTIONS | |
{ | |
.imports (NOLOAD) : { | |
/* TIM1_UP_TIM10_IRQHandle 0800c0a4 ed c0 01 08 addr LAB_0801c0ec+1 */ | |
fw_base = 0x0800c000; | |
ptr_timer = 0x0800c0a4; | |
old_timer = 0x0801c0ed; | |
LED_BUFFER = 0x20000304; | |
REFRESH_BUFFER = 0x20006754; | |
MODE = 0x2000058c; | |
ptr_onKeyDown = 0x0800fd08; | |
old_onKeyDown = 0x0800fc5d; | |
ptr_loop = 0x0800cde6; | |
old_loop = 0x0800fcee; | |
ptr_updateScreen = 0x0800fe16; | |
old_updateScreen = 0x0800f9e0; | |
TICKMS = 0x200009c0; /* millisecond timer */ | |
ptr_startup = 0x0800cc4a; | |
old_startup = 0x0800d98c; | |
} | |
.text : { | |
*(.text*) | |
*(.rodata*) | |
_sidata = .; | |
} >rom | |
.data : { | |
_sdata = .; | |
*(.data) | |
_edata = .; | |
} >ram AT >rom | |
.bss : { | |
_sbss = .; | |
*(.bss) | |
_ebss = .; | |
} >ram | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var fs = require("fs"); | |
var buf1 = fs.readFileSync("LPMiniMK3-407.bin"); | |
var buf2 = fs.readFileSync("code.bin"); | |
var buf3 = fs.readFileSync("code.dat"); | |
var pad = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0]) | |
if (buf1.length + pad.length != 0x104b0) | |
throw "error" | |
var buf = Buffer.concat([buf1, pad, buf2, buf3]); | |
var symbols = fs.readFileSync("code.txt").toString().split("\n").map(x=>x.split(" ")); | |
function getSymbol(name) | |
{ | |
var addr = symbols.find(x=>x[2] == name)[0]; | |
console.log(name, addr); | |
if (!addr) | |
throw "no symbol" | |
var sym = parseInt("0x"+addr); | |
console.log(`${name} at 0x${sym.toString(16)}`); | |
return sym; | |
} | |
var firmwareBase = getSymbol("fw_base"); | |
var vectorPtr = getSymbol("ptr_onKeyDown"); | |
var vectorOrg = getSymbol("old_onKeyDown"); | |
var vectorNew = getSymbol("new_onKeyDown") | 1; | |
swizzle(vectorPtr, vectorOrg, vectorNew); | |
var vectorPtr = getSymbol("ptr_startup"); | |
var vectorOrg = getSymbol("old_startup"); | |
var vectorNew = getSymbol("new_startup") | 1; | |
redirect(vectorPtr, vectorOrg, vectorNew); | |
redirect(getSymbol("ptr_loop"), getSymbol("old_loop"), getSymbol("new_loop")); | |
redirect(getSymbol("ptr_updateScreen"), getSymbol("old_updateScreen"), getSymbol("new_updateScreen")); | |
function swizzle(ptr, pold, pnew) | |
{ | |
console.log(`swizzling at ${ptr.toString(16)} from ${pold.toString(16)} to ${pnew.toString(16)}`); | |
ptr -= firmwareBase; | |
if (buf[ptr+0] != ((pold>>0)&0xff) || | |
buf[ptr+1] != ((pold>>8)&0xff) || | |
buf[ptr+2] != ((pold>>16)&0xff) || | |
buf[ptr+3] != ((pold>>24)&0xff)) | |
throw "error"; | |
buf[ptr+0] = (pnew>>0)&0xff; | |
buf[ptr+1] = (pnew>>8)&0xff; | |
buf[ptr+2] = (pnew>>16)&0xff; | |
buf[ptr+3] = (pnew>>24)&0xff; | |
} | |
function nop(base, pairs) | |
{ | |
for (var i=0; i<pairs; i++) | |
{ | |
buf[base+i*2-firmwareBase] = 0x00; | |
buf[base+i*2+1-firmwareBase] = 0xbf; | |
} | |
} | |
function redirect(address, oldtarget, newtarget) | |
{ | |
console.log(`swizzling at ${address.toString(16)} from ${oldtarget.toString(16)} to ${newtarget.toString(16)}`); | |
baddr = address - firmwareBase; | |
var bytes = [buf[baddr], buf[baddr+1], buf[baddr+2], buf[baddr+3]] | |
var curtarget = thumbBlDisassembly(bytes, address); | |
if (oldtarget != curtarget) | |
throw "error"; | |
console.log("target", oldtarget.toString(16), curtarget.toString(16)); | |
var newbytes = thumbBlAssembly(address, newtarget); | |
if ((thumbBlDisassembly(newbytes, address)|1) != (newtarget|1)) | |
throw "error"; | |
buf[baddr+0] = newbytes[0]; | |
buf[baddr+1] = newbytes[1]; | |
buf[baddr+2] = newbytes[2]; | |
buf[baddr+3] = newbytes[3]; | |
} | |
function thumbBlAssembly(origin, target) | |
{ | |
var offset = target - (origin + 4); | |
if (offset < 0) | |
throw "error"; | |
offset >>= 1; | |
offset &= 0x00FFFFFF; | |
var words = [0xF000 | ((offset >> 11) & 0x7FF), | |
0xF800 | (offset & 0x7FF)]; | |
return [words[0] & 255, words[0] >> 8, words[1] & 255, words[1] >> 8]; | |
} | |
function thumbBlDisassembly(bytes, address) | |
{ | |
var words = [bytes[0] | (bytes[1] << 8), bytes[2] | (bytes[3] << 8)] | |
console.log(address.toString(16), words[0].toString(16), words[1].toString(16)); | |
if ((words[0] & 0xf800) != 0xf000 || (words[1] & 0xf800) != 0xf800) | |
throw "error"; | |
var offset = (words[1] & 0x7ff) | ((words[0] & 0x7ff)<<11) | |
if (offset & 0x200000) | |
offset |= 0xfff00000 | |
console.log("ofs", offset.toString(16)); | |
offset <<= 1; | |
return address+offset+4; | |
} | |
fs.writeFileSync("final.bin", buf) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
set -e | |
arm-none-eabi-g++ -fno-exceptions -fno-rtti -fno-common -Wno-psabi -Os -g -mcpu=cortex-m4 -mlittle-endian \ | |
-mfpu=fpv4-sp-d16 -mthumb -nostartfiles -ffunction-sections -T code.lds code.cpp -o code.elf | |
arm-none-eabi-objdump -S -marm -d ./code.elf > code.s | |
arm-none-eabi-nm ./code.elf > code.txt | |
arm-none-eabi-objcopy -j .text -O binary ./code.elf code.bin | |
arm-none-eabi-objcopy -j .data -O binary ./code.elf code.dat | |
node combine.js | |
./bintosyx /minimk3 444 ./final.bin final.syx | |
rm code.txt code.elf code.bin code.dat final.bin code.s | |
#flash with (up up down down left right left right): https://fw.mat1jaczyyy.com/firmware |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment