Powershot A420


A BETA version of CHDK is available for the Powershot A420 with firmware version 1.00b from the Autobuild Server

Reviews: Digital Cameras Review, DPR review

Firmware information[]

The trick with the ver.req file works on the A420 as well, with the following result:

Canon PowerShot A420
P-ID:310F  PAL

Firmware Ver GM1.00B
No error
Dec 6 2005   09:17:55

pressing DISP button again results in:

Canon PowerShot A420
P-ID:310F  PAL

Adj Ver.005.001

Technical data[]

  • Digic II image processor
  • VxWorks operating system
  • Sensor: 4 MP, 1/3-inch CCD type
  • Lens: 39-125mm equiv, F2.8-5.1, 3.2x optical zoom
  • LCD Monitor: 1.8-inch TFT, ~77,000 pixels
  • Optical Viewfinder
  • 5-point AiAF/1-point AF (fixed to center)
  • Storage: SD / MMC
  • Power: 2x AA, optional AC Adapter Kit ACK800
  • Dimensions: 103.3 x 51.8 x 40.2 mm , Weight: 150g (5.29 oz.)

For developers[]


Firmware dumps[]

  • firmware version 1.00B

Download location for firmware dumps:
P&S firmware dumps mirror


Stubs.s first try[]

Stubs.s was copied from A610 sub 100e and edited by firmware comparison. kbd_pwr_off and kbd_pwr_on was not found entirely. I've replaced them with a null function.

If you want to copy it to a file, it's easier from the wiki edit mode.

The functions before kbd_p1_f may need some revision.


#include "stubs_asm.h"
NSTUB(AllocateMemory, 0xffc01b20)
NSTUB(AllocateUncacheableMemory, 0xffc048f4)
NSTUB(Close, 0xFFC5A42C)
NSTUB(CreatePhysicalVram, 0xFFD092F0)
NSTUB(CreateTask, 0xffc11260)
NSTUB(CreateTaskStrict, 0xffc12300)
NSTUB(DisableDispatch, 0xffc11084)
NSTUB(DisplayImagePhysicalScreen, 0xFFD0859C)
NSTUB(EnableDispatch, 0xffc11100)
NSTUB(ExecuteEventProcedure, 0xFFC0680C)
NSTUB(ExitTask, 0xffc11620)
NSTUB(FreeMemory, 0xffc01b38)
NSTUB(FreeUncacheableMemory, 0xffc04928)
NSTUB(GetCurrentAvValue, 0xFFE5BF44)
NSTUB(GetCurrentTargetDistance, 0xFFE5E054)
NSTUB(GetFocusLensSubjectDistance, 0xFFE52234)
NSTUB(GetParameterData, 0xFFD3D590)
NSTUB(GetPropertyCase, 0xFFC143EC)
NSTUB(GetSystemTime, 0xFFC04B2C)
NSTUB(GetZoomLensCurrentPoint, 0xFFE41344)
NSTUB(GetZoomLensCurrentPosition, 0xFFE41358)
NSTUB(IsStrobeChargeCompleted, 0xFFD22EF0)
NSTUB(LockMainPower, 0xFFD38918)
NSTUB(MakeDirectory, 0xFFC5CB08)
NSTUB(Mount_FileSystem, 0xFFC596CC)
NSTUB(MoveFocusLensToDistance, 0xFFE5E2F4)
NSTUB(MoveZoomLensWithPoint, 0xFFE41224)
NSTUB(Open, 0xFFC5A404)
NSTUB(PhySw_testgpio, 0xFFC17B68)
NSTUB(ProtectFile, 0xFFC55194)
NSTUB(Read, 0xFFC5A4C0)
NSTUB(RefreshPhysicalScreen, 0xFFD4EAE0)
NSTUB(Remove, 0xFFC5A44C)
NSTUB(SetParameterData, 0xFFD3D4B0)
NSTUB(SetPropertyCase, 0xFFC143EC)
NSTUB(SleepTask, 0xFFC11174)
NSTUB(TakeSemaphore, 0xFFC10C70)
NSTUB(UnlockMainPower, 0xFFD389CC)
NSTUB(Unmount_FileSystem, 0xFFC59750)
NSTUB(UpdateMBROnFlash, 0xFFC59938)
NSTUB(VbattGet, 0xFFC1B014)
NSTUB(Write, 0xFFC5A4CC)
NSTUB(_log, 0xFFE9381C)
NSTUB(_log10, 0xFFE8FCF4)
NSTUB(_pow, 0xFFE8FE7C)
NSTUB(_sqrt, 0xFFE91B1C)
NSTUB(chdir, 0xFFEA00F0)
NSTUB(close, 0xFFE9FA30)
NSTUB(closedir, 0xFFE9CEB8)
NSTUB(free, 0xFFC01B38)
NSTUB(ints_disable, 0xFFC0D6E0)
NSTUB(ints_enable, 0xFFC0D6EC)
NSTUB(ioctl, 0xFFE9FB70)
NSTUB(iosDevAdd, 0xFFEA0C50)
NSTUB(iosDrvInstall, 0xFFEA0F14)
NSTUB(isalpha, 0xFFE96F5C)
NSTUB(isdigit, 0xFFE96F8C)
NSTUB(islower, 0xFFE96FBC)
NSTUB(isspace, 0xFFE97004)
NSTUB(isupper, 0xFFE9701C)
NSTUB(kbd_p1_f, 0xFFC16910)
NSTUB(kbd_p1_f_cont, 0xFFC1691C)
NSTUB(kbd_p2_f, 0xFFC16CEC)
NSTUB(kbd_pwr_off, 0xFFEA8F80)  //null stub	//not found
NSTUB(kbd_pwr_on, 0xFFEA8F80)  //null stub	//not found
NSTUB(kbd_read_keys_r2, 0xFFC17618)
NSTUB(localtime, 0xFFE9B6AC)
NSTUB(lseek, 0xFFE9FB74)
NSTUB(malloc, 0xFFEA2A70)
NSTUB(memcmp, 0xFFE9AA8C)
NSTUB(memcpy, 0xFFE9AAC8)
NSTUB(memset, 0xFFE9AB40)
NSTUB(mkdir, 0xFFC5A614)
NSTUB(open, 0xFFEA0074)
NSTUB(opendir, 0xFFE9CEEC)
NSTUB(qsort, 0xFFE86FC0)
NSTUB(rand, 0xFFE9A310)
NSTUB(read, 0xFFE9FA90)
NSTUB(readdir, 0xFFE9CE84)
NSTUB(rename, 0xFFEA007C)
NSTUB(rewinddir, 0xFFE9CEAC)
NSTUB(srand, 0xFFE9A334)
NSTUB(stat, 0xFFE9CF80)
NSTUB(strcat, 0xFFE9AB60)
NSTUB(strchr, 0xFFE9AB8C)
NSTUB(strcmp, 0xFFE9ABB0)
NSTUB(strcpy, 0xFFE9AD44)
NSTUB(strlen, 0xFFE9AEA8)
NSTUB(strncmp, 0xFFE9AF0C)
NSTUB(strncpy, 0xFFE9AF50)
NSTUB(strpbrk, 0xFFE9AF98)
NSTUB(strrchr, 0xFFE9AFD4)
NSTUB(strtol, 0xFFE9A728)
NSTUB(taskCreateHookAdd, 0xFFEA56D0)
NSTUB(taskDeleteHookAdd, 0xFFEA560C)
NSTUB(taskIdListGet, 0xFFEAF698)
NSTUB(taskLock, 0xFFEAFD54)
NSTUB(taskName, 0xFFEAF590)
NSTUB(taskResume, 0xFFEAF974)
NSTUB(taskSuspend, 0xFFEAF7A0)
NSTUB(taskUnlock, 0xFFEAFDFC)
NSTUB(time, 0xFFE9C3F8)
NSTUB(utime, 0xFFE9D014)
NSTUB(vsprintf, 0xFFE9E7D8)
NSTUB(write, 0xFFE9FB00)


I ain't got no idea, where should i have to get the proper '+ 0x30000' value from, so i left it untouched. The others are fixed, i hope.

#include "lolevel.h"
#include "platform.h"
#include "core.h"

/* Ours stuff */
extern void createHook (void *pNewTcb);
extern void deleteHook (void *pTcb); 

void boot();

/* "relocated" functions */
void __attribute__((naked,noinline)) h_usrInit();
void __attribute__((naked,noinline)) h_usrKernelInit();
void __attribute__((naked,noinline)) h_usrRoot(); 
void boot()
     long *canon_data_src = (void*)0xFFEB60C0;
     long *canon_data_dst = (void*)0x1900;
     long canon_data_len = 0xCEB0;
     long *canon_bss_start = (void*)0xE7B0; // canon_data_dst+canon_data_len
     long canon_bss_len = 0x9EF70 - 0xCEB0;
     long i; 

    asm volatile ( 
	"MRC     p15, 0, R0,c1,c0\n" 
	"ORR     R0, R0, #0x1000\n"
	"ORR     R0, R0, #4\n"
	"ORR     R0, R0, #1\n"
	"MCR     p15, 0, R0,c1,c0\n"



   asm volatile (
	"MRC     p15, 0, R0,c1,c0\n" 
	"ORR     R0, R0, #0x1000\n"
	"BIC     R0, R0, #4\n"
	"ORR     R0, R0, #1\n"
	"MCR     p15, 0, R0,c1,c0\n"


void h_usrInit()
   asm volatile (
	"STR     LR, [SP,#-4]!\n"
	"BL      sub_FFC01968\n"
	"MOV     R0, #2\n"
	"MOV     R1, R0\n"
	"BL      sub_FFE9C438\n"// unknown_libname_765 ; "Canon A-Series Firmware"
	"BL      sub_FFE8DAA8\n"// excVecInit
	"BL      sub_FFC011C4\n"
	"BL      sub_FFC01728\n"
	"LDR     LR, [SP],#4\n"
	"B       h_usrKernelInit\n"

void  h_usrKernelInit()
   asm volatile (
	"STMFD   SP!, {R4,LR}\n"
	"SUB     SP, SP, #8\n"
	"BL      sub_FFE9C938\n"	//classLibInit
	"BL      sub_FFEAF720\n"	//taskLibInit
	"LDR     R3, =0xD7C0\n"
	"LDR     R2, =0x9BC00\n"
	"LDR     R1, [R3]\n"
	"LDR     R0, =0x9E930\n"
	"MOV     R3, #0x100\n"
	"BL      sub_FFEA8830\n"	//qInit
	"LDR     R3, =0xD780\n"
	"LDR     R0, =0xDFC8\n"
	"LDR     R1, [R3]\n"
	"BL      sub_FFEA8830\n"	//qInit
	"LDR     R3, =0xD83C\n"
	"LDR     R0, =0x9E904\n"
	"LDR     R1, [R3]\n"
	"BL      sub_FFEA8830\n"	//qInit
	"BL      sub_FFEB42A0\n"	//workQInit
	"BL      sub_FFC012B0\n"
	"MOV     R4, #0\n"
	"MOV     R3, R0\n"
	"MOV     R12, #0x800\n"
	"LDR     R0, =h_usrRoot\n"	//sub_FFC01A64
	"MOV     R1, #0x4000\n"
	"LDR     R2, =0xCEF70\n"	//0x9EF70 + 0x30000
	"STR     R12, [SP]\n"
	"STR     R4, [SP,#4]\n"
	"BL      sub_FFEAC960\n"	//kernelInit
	"ADD     SP, SP, #8\n"
	"LDMFD   SP!, {R4,PC}\n"

static long drv_struct[16];

static long dh_err()
   return -1;

static void drv_self_hide()
   long drvnum;
   drvnum = _iosDrvInstall(dh_err,dh_err,dh_err,dh_err,dh_err,dh_err,dh_err);
   if (drvnum >= 0)
	_iosDevAdd(drv_struct, "A/DISKBOOT.BIN", drvnum);

void  h_usrRoot()
   asm volatile (
	"STMFD   SP!, {R4,R5,LR}\n"
	"MOV     R5, R0\n"
	"MOV     R4, R1\n"
	"BL      sub_FFC019D0\n"
	"MOV     R1, R4\n"
	"MOV     R0, R5\n"
	"BL      sub_FFEA15CC\n"
	"MOV     R1, R4\n"
	"MOV     R0, R5\n"
	"BL      sub_FFEA2044\n"
	"BL      sub_FFC017E8\n"
	"BL      sub_FFC01704\n"
	"BL      sub_FFC01A10\n"
	"BL      sub_FFC019F4\n"
	"BL      sub_FFC01A3C\n"
	"BL      sub_FFC019C4\n"



   asm volatile (
	"LDMFD   SP!, {R4,R5,LR}\n"
	"B       sub_FFC0136C\n"