Canon basic binary loader
This script loads and boots the specified ARM binary. The binary should be unencoded, and loadable at 0x1900
After a CHDK build, a suitable binary can be found at loader/<camera>/main.bin.
Tested on a540 (vxworks) and D10 (dryos)
Free memory must be > the size of the binary. This may be a problem on some cameras, especially if CHDK is already running and there are images on the camera.
original discussion thread with background information http://chdk.setepontos.com/index.php?topic=5648.0
' bootbin is the image to load. It must be an unencoded arm binary
DIM bootbin = "A/MAIN.BIN"
DIM lcdmsg=0
DIM msgstr=0
PRIVATE SUB RegisterProcs()
' Newest cams (Dryos rel 43 and later) only have System.Create()
' on older dryos cams SystemEventInit is an alias for System.Create()
' ExecuteEventProcedure does is not registered by default on vx,
' but calling an unregistered is not fatal
if System.Create() = -1 then
SystemEventInit()
end if
if ExecuteEventProcedure("UI_RegistDebugEventProc") = -1 then
ExecuteEventProcedure("UI.CreatePublic")
end if
ExecuteEventProcedure("DispDev_EnableEventProc")
END SUB
PRIVATE SUB InitMsg()
lcdmsg = ExecuteEventProcedure("LCDMsg_Create")
' not default black
if lcdmsg >= 0 then
LCDMsg_ChangeColor(lcdmsg,2)
LCDMsg_SetStr(lcdmsg,"started")
end if
msgstr = AllocateMemory(80)
' truncate log
msgfile = Fopen_Fut("A/CBLOADER.LOG","w")
if msgfile <> 0 then
Fclose_Fut(msgfile)
end if
END SUB
PRIVATE SUB PutMsg(msg)
if lcdmsg >= 0 then
LCDMsg_SetStr(lcdmsg,msg)
end if
msgfile = Fopen_Fut("A/CBLOADER.LOG","a")
if msgfile <> 0 then
Fwrite_Fut(msg,strlen(msg),1,msgfile)
Fwrite_Fut("\n",1,1,msgfile)
Fclose_Fut(msgfile)
end if
END SUB
' put some ARM code in a buffer
' this should be in uncacheable memory, but function is not available on older cams
' in practice, loading the main image should ensure all this is flushed out
' pad binary to > 4k or so if needed
' can't use strings with \xHH because older cams don't support
' parameters:
' R0 source address
' R1 size
' never returns, saves nothing on the stack
PRIVATE SUB MakeLoader()
buf = AllocateMemory(76)
p = buf
*p = 0xee113f10 ' MRC p15, 0, R3, c1, c0, 0
p = p + 4
*p = 0xe3c33a01 ' BIC R3, R3, #0x1000 // icache bit
p = p + 4
*p = 0xe3c33004 ' BIC R3, R3, #0x4 // dcache bit
p = p + 4
*p = 0xee013f10 ' MCR p15, 0, R3, c1, c0, 0
p = p + 4
*p = 0xe3a03000 ' MOV R3, #0
p = p + 4
*p = 0xee073f9a ' MCR p15, 0, R3,c7,c10, 4 // drain write buffer
p = p + 4
*p = 0xee073f15 ' MCR p15, 0, R3,c7,c5 // flush icache
p = p + 4
*p = 0xee073f16 ' MCR p15, 0, R3,c7,c6 // flush dcache
p = p + 4
*p = 0xe10f4000 ' MRS R4, CPSR
p = p + 4
*p = 0xe3844080 ' ORR R4, R4, #0x80
p = p + 4
*p = 0xe12ff004 ' MSR CPSR_cxsf, R4 // disable IRQs
p = p + 4
*p = 0xee195f11 ' MRC p15, 0, R5, c9, c1, 0 // read data TCM config
p = p + 4
*p = 0xe1a05625 ' MOV R5, R5, LSR#12 // clear the lower 12 bits
p = p + 4
*p = 0xe7935605 ' LDR R5, [R3, R5, LSL#12] // R3 is still 0
p = p + 4
*p = 0xe1a02001 ' MOV R2, R1
p = p + 4
*p = 0xe1a01000 ' MOV R1, R0
p = p + 4
*p = 0xe3a00c19 ' MOV R0, #0x1900
p = p + 4
*p = 0xe3a03c19 ' MOV R3, #0x1900
p = p + 4
*p = 0xe12fff35 ' BLX R5
MakeLoader = buf
END SUB
PRIVATE SUB LoadNBoot()
loader = MakeLoader()
fd = Open(bootbin,0)
IF fd = -1 THEN
PutMsg("bootbin size fail")
EXIT SUB
END IF
imgsize = Lseek(fd,0,2)
Close(fd)
imgbuf = AllocateMemory(imgsize)
IF imgbuf = 0 THEN
sprintf(msgstr,"alloc %d fail",imgsize)
PutMsg(msgstr)
EXIT SUB
END IF
fd = Fopen_Fut(bootbin,"r")
IF fd = 0 THEN
sprintf(msgstr,"open %s fail",bootbin)
PutMsg(msgstr)
EXIT SUB
END IF
rcnt = Fread_Fut(imgbuf,1,imgsize,fd)
Fclose_Fut(fd)
IF rcnt <> imgsize THEN
sprintf(msgstr,"read %d fail",imgsize)
PutMsg(msgstr)
FreeMemory(imgbuf)
EXIT SUB
END IF
sprintf(msgstr,"%s %d",bootbin,imgsize)
PutMsg(msgstr)
Wait(500)
' register the start of loader as a function
ExportToEventProcedure("loader_func",loader)
DispCon_TurnOffDisplay()
' if starting is very slow, watchdog can hit before loading is complete
' but may stay on indefinitely if we crash
StopWDT()
loader_func(imgbuf,imgsize)
' if loader_func could return, we could try to restore
'StartWDT()
'DispCon_TurnOnDisplay()
END SUB
PRIVATE SUB Initialize()
RegisterProcs()
InitMsg()
LoadNBoot()
END SUB