Parent: 2.0.4 AJ
This page is follows attempts to use ML to output current Zoom settings .. and to enable zoom while recording (No idea what will happen!)
ZOOM during recording -> The following is what I'm aiming to change the Canon firmware too following my static code analysis in IDA:
ZOOM during recording .. hmmm .. probably need to change the following: 0xFF8DF92C CMPNE R0, #4 ; AJ_LiveView_main() : Only allow Zoom in specific states to 0xFF8DF92C CMP R0, #99 ; Allow Zoom irrespective of State and 0xFF8E3084 CMP R0, #0 ; AJ_ChangeVDInterrupt() : IF "LVRecState".cur_state = INIT to 0xFF8E3084 CMP R0, R0 ; Allow Zoom irrepective of "LVRecState"
.
Step 1 - Checking ML hardcoded addresses correspond to the subroutine and structs my 2.0.4 firmware. As I check each module - I'll at it to this banner [Checked] stubs-5d2.204.S :
stubs-5d2.204.S http://bitbucket.org/hudson/magic-lantern/src/7309f68e78ae/stubs-5d2.204.S
NSTUB( 0xFF810894, cstart ) = TH_cstart NSTUB( 0xFFC456C0, bzero32 ) = AJ_memset_to.Zero_R0.addr_R1.Len NSTUB( 0xFF811DBC, init_task ) = TH_init_task NSTUB( 0xFF817470, create_init_task ) = TH_create_init_task NSTUB( 0xFF86AF48, DebugMsg ) = TH_DebugMsg NSTUB( 0x1934, task_dispatch_hook ) = aAJ_0x1934_task_dispatch_hook_struct_0x00_to_0x10 NSTUB( 0x13420, additional_version )= aAJ_0x13420_additional_version NSTUB( 0xC0220000, camera_engine ) = aAJ_0xC0220000_HDMI_maybe_hotplug_struct1_0x00_to_0x70 NSTUB( 0xFF81C4DC, register_func ) = AJ_setup_list_command_names NSTUB( 0xFF86AEC8, dmstart ) = TH_dmstart NSTUB( 0xFF86B7DC, dumpf ) = TH_dumpf NSTUB( 0xFF9B7164, vsnprintf ) = TH_vsnprintf NSTUB( 0xFF86E210, msleep ) = TH_msleep NSTUB( 0xFF86E2C8, task_create ) = AJ_task_create_R0.name_R1.priority_R2.unk_R3.Sub_SP.taskStruct NSTUB( 0xFF86AF08, dmstop ) = TH_dmstop NSTUB( 0xFF9AA9FC, FIO_Open) = TH_FIO_Open NSTUB( 0xFF9AAAB0, FIO_CreateFile ) = TH_FIO_CreateFile NSTUB( 0xFF9AAB58, FIO_CloseFile ) = TH_FIO_CloseFile NSTUB( 0xFF9AB14C, FIO_GetFileSize ) = TH_FIO_GetFileSize NSTUB( 0xFF9AAF98, FIO_WriteFile ) = TH_FIO_WriteFile NSTUB( 0xFF9AADE8, FIO_ReadFile ) = TH_FIO_ReadFile NSTUB( 0xFF86DE54, give_semaphore ) = TH_give_semaphore NSTUB( 0xFF86DD6C, take_semaphore ) = TH_take_semaphore NSTUB( 0xFF86BCC4, call ) = TH_call NSTUB( 0xFF86B294, dm_set_store_level ) = TH_dm_set_store_level NSTUB( 0xFF85F0D4, prop_register_slave ) = TH_prop_register_slave NSTUB( 0xFF85F20C, prop_request_change ) = TH_prop_request_change NSTUB( 0xFF85F04C, prop_deliver ) = TH_prop_deliver NSTUB( 0xFF85F1A8, prop_cleanup ) = TH_prop_cleanup NSTUB( 0xFF86DC0C, create_named_semaphore ) = TH_create_named_semaphore NSTUB( 0xFFA6BD14, gui_task_create ) = TH_gui_task_create NSTUB( 0xFF8696BC, LoadCalendarFromRTC ) = TH_LoadCalendarFromRTC NSTUB( 0xFF86F150, malloc ) = AJ_malloc_R0_bytes NSTUB( 0xFF86F4E0, free ) = TH_free_memory_at_R0 NSTUB( 0xFF812E44, cli_save ) = TH_cli_save_AJ_IRQsave NSTUB( 0xFF812E58, sei_restore ) = TH_sei_restore_AJ_IRQrestore NSTUB( 0xFF85961C, _audio_ic_write ) = TH_sys_audio_ic_write NSTUB( 0xFF85944C, _audio_ic_read ) = TH_sys_audio_ic_read NSTUB( 0xFF85B0C8, sounddev_task ) = TH_sounddev_task NSTUB( 0x2360, sounddev ) = aAJ_0x2360_sounddev_0x00_to_0x5C NSTUB( 0xFF87CBD0, strcpy ) = TH_strcpy_From.R1_To.R0 NSTUB( 0xFFA0FD18, ptp_register_handler ) = TH_ptp_register_handler NSTUB( 0xFF92EA48, gui_lock ) = TH_gui_lock NSTUB( 0xFF893CD8, prop_request_icu_auto_poweroff ) = TH_prop_request_icu_auto_poweroff NSTUB( 0xFFC455CC, memcpy ) = AJ_memcpy_FromR1_ToR0_LenR2 NSTUB( 0xFF86C704, oneshot_timer ) = TH_oneshot_timer__R0.msec__R1.Sub.If.Expire__R2.Sub__R3.arg NSTUB( 0xFF81DE08, hotplug_task ) = TH_hotplug_task NSTUB( 0x1AA4, hotplug_struct ) = aAJ_0x1AA4_hotplug_struct_0x00_to_0x44_initialized NSTUB( 0x1AD8, hotplug_usb_buf ) = aAJ_0x1AA4_hotplug_struct_0x34_hotplug_usb_state [AJ checked Ok] ML refs is a 4Byte Buffer. I think it's the USB Hotplug Status. NSTUB( 0xFF864678, dispcheck ) = TH_dispcheck NSTUB( 0x27624, bmp_vram_info ) = aAJ_0x27624_bmp_vram_info_0x00_to_0x08 NSTUB( 0x38920, vram_info ) = aAJ_0x38920_vram_info_0x00_to_0x04 NSTUB( 0xFFA413FC, vram_get_number ) = TH_vram_get_number NSTUB( 0xFF8773A4, task_trampoline ) = TH_task_trampoline NSTUB( 0x208A4, cf_device ) = aAJ_0x208A4_cf_device NSTUB( 0x2BA0, dm_names ) = aAJ_0x2BA0_dm_names NSTUB( 0xFFA6BE34, gui_task_destroy ) = TH_gui_task_destroy NSTUB( 0xFF82399C, gui_main_task ) = AJ_gui_main_task NSTUB( 0xFF82434C, gui_init_end ) = TH_gui_init_end NSTUB( 0x38F0, gui_timer_struct ) = aAJ_0x38F0_gui_timer_struct_0x00_to_0x38 NSTUB( 0x1C4C, gui_main_struct ) = aAJ_0x1C4C_gui_main_struct_0x00_to_0x34 NSTUB( 0xFF86D96C, msg_queue_receive ) = TH_msg_queue_receive NSTUB( 0xFF891BA0, gui_local_post ) = TH_gui_local_post NSTUB( 0xFF8916FC, gui_change_mode ) = TH_gui_change_mode NSTUB( 0xFF891F98, gui_other_post ) = TH_gui_other_post NSTUB( 0xFF8921F0, gui_post_10000085 ) = TH_gui_post_10000085 NSTUB( 0xFF892830, gui_init_event ) = AJ_gui_init_event NSTUB( 0xFF8922A4, gui_change_shoot_type_post ) = TH_gui_change_shoot_type_post NSTUB( 0xFF89233C, gui_change_lcd_state_post ) = TH_gui_change_lcd_state_post NSTUB( 0xFFA6BBC4, ctrlman_dispatch_event ) = TH_ctrlman_dispatch_event NSTUB( 0xFF890188, gui_massive_event_loop ) = TH_gui_massive_event_loop NSTUB( 0xFF9B3910, gui_timer_something ) = TH_gui_timer_something NSTUB( 0xFFCB48CC, audio_thresholds ) = aTH_0xFFCB48CC_audio_thresholds NSTUB( 0xFF85B438, sounddev_active_in ) = TH_sounddev_active_in NSTUB( 0xFF9B9FD0, alloc_dma_memory ) = TH_alloc_dma_memory NSTUB( 0xFF9BA004, free_dma_memory ) = TH_free_dma_memory_at_R0
.
Step 2 - Getting to Grips with Magic-Lantern [AJ] If I find a logical way to read the ML code (for introductory purposes), I'll create another page (or reference it, if one already exists)
There is quite a few parts to Magic Lantern. Doxygen (which I'm new to) produces lots of 'documentation' ... but what is the quickest way to understand how it all works?
5d-hack.c
- Not sure why version.h is included twice
- function zero_bss() - use a while loop to do a memset().
memset() is available in the firmware.
I'm not sure how long the while loop take -> is it worth replacing for a faster startup? - function blob_memcpy(). Do we need a routine that does memcpy's with a resoution of %4 if there is a memcpy() in the firmware that has a resolution of 1 byte (and is efficiently coded). I presume that memcpy can copy the code that is currently executing as long as the code is not modified.
Let have a quick look at what the dryos 2.0.4 is upto at startup - and then look at what 5d-hack.c does.
Decided to put this in a separate page: 2.0.4 Bootstrap
--- I'll be over there intermittently ---
config.c focus.c gui.c pack-fir.c reloc.c version.c
audio.c debug.c font-huge.c hotplug.c property.c script.c zebra.c
bmp.c decrypt-block.c font-large.c lens.c ptp.c spotmeter.c
bootflags.c dissect_fw.c font-med.c liveview.c pymite-plat.c stdio.c
bracket.c dumper.c font-small.c menu.c reboot.c timecode.c
--- This section is unfinished ---
Step 3 - Using ML to Check Stateobjects [AJ] Need this because my 'zoom' change required my understanding of LV_Rec state object to be correct.
So ... what would be the easiest way to get information printed to the LCD?
First though is that I find the audio level code that TH created - and add a 'printf' that outputs the current LV_Rec state.
- Where's the code? -> from list of *.c progs in Step2 -> the most likely is audio.c -> looking at code -> draw_meters() looks like the best location.
- Next - what do I want to print out?
aAJ_0x44FC_LiveView_struct_0x2C_LV_StateObj - The Live View State Object aAJ_0x44FC_LiveView_struct_0x30_LVRec_StateObj - The Live View Recording State Object
- What does a state object look like? ( from http://magiclantern.wikia.com/wiki/2.0.4_StateObjects )
32B struct:[0x00] "StateObject" [0x04] p.StateObjectName = parm1 [0x08] p.inital_state = Always_0 = parm2 [0x0C] AJ_StateObj() [0x10] p.ValSubList = parm3 [0x14] p.total_inputs = parm4 [0x18] p.total_states [0x1C] p.current_state = parm2 = 0
- Checking Magic Lantern to see if there is a structure that exactly corresponds to this -> state_object.h
Note: I am interested in current_state.
struct state_object { const char * type; // off 0x00, "StateObject" const char * name; // off 0x04, arg 0 uint32_t auto_sequence; // off 0x08, arg 1 // off 0x0c, always 0xff99a228 ? void (*callback)( struct state_object * self, void * arg1, uint32_t input, void * arg3, void * arg4 ); // Points to an array of size [max_inputs][max_states] struct state_callback * callbacks; // off 0x10 uint32_t max_inputs; // off 0x14, arg 2 uint32_t max_states; // off 0x18, arg 3 uint32_t state; // off 0x1c, initially 0 };
ML's auto_sequence = AJ's initial_state
ML's state = AJ's current_state.
Everything is ML matches my understanding of 2.0.4 -> I can use the ML state_object.
- To answer the 'always 0xff99a228 ?' question in the code above:
[AJ] Yes this is always set to a standard routine used to jump to the next state in the state machine.
My view is that Canon tried to use this .... but then found that it didn't work very well when they tried to extend the LV state machine to allow a more dynamic LVRec statute machine. Consequently ... they have a lot of 'fudge code' that maintains both LVRec and LV state machines current state .. almost like movie recording was an afterthought.
- My initial attempt to dump the StateObject wasn't 100% right.... I've just gone overboard and typecast every single step of the printout ... and one variable came out correctly! Yee-haaah! That's one very little step forward for AJ ... but a happy little step.
- Let me see if can get 'unmessify' (is that a real word?) the code and make it look heavenly again. Once we have a state object dumping routine ... it could prove usefull in understanding how the state machines working in real time.
- Although State Object information is interesting ... it's slightly of the 'zoom' mark .. and so I wrote the following.
This piece of code outputs the Zoom level (0,1 or 2).
It's the first step .. and confirms that my earlier static analysis was correct.
- Almost ready to Change the ASM code . I might need to use a TH style hack to relocate the code. Not sure yet.
/********************************************** * aj_dump_LiveViewMgr_struct() - * ***********************************************/ static void aj_dump_LiveViewMgr_struct( void ) { int *LvMgr_ptr = (int *) ( 0x44FC + 0xB8); int LvMgr_addr = *LvMgr_ptr; // LiveViewMgr_struct is 0x29D8 bytes static int g_aj_counter1 = 0; static int g_aj_counter2 = 0; static unsigned int zoom = 0; int name = LvMgr_addr; int LVmagSubBank = LvMgr_addr +0xC0; int ZoomMode = LvMgr_addr +0xC4; int EngIdx = LvMgr_addr +0xC8; int FrameRate = LvMgr_addr +0xCC; int LvState1 = LvMgr_addr +0x3FC; int LvState2 = LvMgr_addr +0x400; int RecMovSubBank = LvMgr_addr +0x948; int b110 = LvMgr_addr +0xB10; int Temperature = LvMgr_addr +0xB14; int Temp = LvMgr_addr +0xB1C; int ZoomLevel = LvMgr_addr +0xCD0; /********************* * Screen counter * *********************/ if (++ g_aj_counter1 == 19) { g_aj_counter1 = 0; if ( ++ g_aj_counter2 == 10) { g_aj_counter2 = 0; if ( ++ zoom == 3) { zoom = 0; } // * (unsigned int *) LVmagSubBank = zoom; * (unsigned int *) ZoomMode = zoom; } } if ( LvMgr_addr == 0 ) { bmp_printf( FONT_SMALL, 0, 0,"LV=null"); } else { bmp_printf( FONT_SMALL, 0, 0,"LV=%X N=%s B=%X z=%X Eng=%X", LvMgr_addr, * (char **) name, * (unsigned int *) LVmagSubBank, * (unsigned int *) ZoomMode, * (unsigned int *) EngIdx ); bmp_printf( FONT_SMALL, 0, 16,"F=%X s1=%X s2=%X bnk=%X", * (unsigned int *) FrameRate, * (unsigned int *) LvState1, * (unsigned int *) LvState2, * (unsigned int *) RecMovSubBank ); bmp_printf( FONT_SMALL, 0, 32,"b110=%X T=%X t=%X z=%X", * (unsigned int *) b110, * (unsigned int *) Temperature, * (unsigned int *) Temp, * (unsigned int *) ZoomLevel ); } /* end of else */ } /* end of aj_dump_LiveViewMgr_struct() */ /* Normal VU meter */ static void draw_meters(void) { aj_dump_LiveViewMgr_struct(); }
.
Using (unsigned int) ... I've return to LVRec and LV state objects:
(aaahhhh ... what on earth is this 'new wiki look'??? its awful - only 1/6th of the screen is now usable?!?!!)
/********************************************** * aj_dump_active_state_objs2() - * ***********************************************/ static void aj_dump_state_objs2( void ) { unsigned int LV_so_ptr = 0x44FC+0x2C; unsigned int LVREC_so_ptr = 0x44FC+0x30; unsigned int LV_state = * ((unsigned int *) ((* (unsigned int *) (LV_so_ptr)) + 0x1C)); unsigned int LVREC_state = * ((unsigned int *) ((* (unsigned int *) (LVREC_so_ptr)) + 0x1C)); static unsigned int LV_max = 0; static unsigned int LVREC_max = 0; if (LV_state > LV_max) LV_max = LV_state; if (LVREC_state > LVREC_max) LVREC_max = LVREC_state; bmp_printf( FONT_SMALL, 0, 0,"LV=%X_%X LVREC=%X_%X", LV_state, LV_max, LVREC_state, LVREC_max ); } /* end of aj_dump_state_objs2() */
.
Here's the current 'thrown together' code that I'm using to look at what is changing in the LiveView_Manager struct.
The top part of the screen is for variables that are 0x0000 -> 0xFFFF.
The bottom part of the screen is for variables that are greater thatn 0xFFFF
/********************************************** * aj_dump_LVMgr() - * ***********************************************/ #define LV_Mgr_sz (0x29D8 / 4) #define X_GAP 72 static void aj_dump_LVMgr( void ) { static unsigned int counter = 0; static unsigned int first_time = 1; unsigned int x; unsigned int max_diffs = 0 ; unsigned int x_pos1 = 0; unsigned int y_pos1 = 0; unsigned int x_pos2 = 0; unsigned int y_pos2 = 240; static unsigned int LVMgr[ LV_Mgr_sz ]; unsigned int LVMgr_struct_ptr = 0x1D78; unsigned int LVMgr_struct = * (unsigned int *) ( LVMgr_struct_ptr ); unsigned int old_val, new_val; /********************************* * Wipe out array on invocation * *********************************/ if (first_time == 1) { first_time = 0; for (x=0; x< LV_Mgr_sz; x++) LVMgr[ x ] = 0; } /************************************************** * counter reset to Zero roughly every 8 secs * **************************************************/ if ( ++counter == 18 * 8) { counter = 0; } else { return; } /****************************** * Clear screen * ******************************/ // Clear the bitmap display, just in case bmp_fill( 0, 0, 0, 720, 480 ); /************************************* * Make sure LV_Mgr struct defined * *************************************/ if ( LVMgr_struct == 0) { bmp_printf( FONT_SMALL, 0, 0,"LVMgr_ptr = %X = NULL", LVMgr_struct_ptr ); return; } /********************** * What has changed * **********************/ for (x=0 ; x< LV_Mgr_sz; x++) { old_val = LVMgr[ x ]; new_val = LVMgr_struct + x * 4; new_val = * (unsigned int *) new_val; if ( old_val == new_val) continue; /***************************** * Here if Value has Changed * *****************************/ LVMgr[ x ] = new_val; max_diffs++; /******************************************************** * Here if there is still space left to print on screen * ********************************************************/ if ( new_val > 0xFFFF ) { if (y_pos2 > 480 - 16) continue; bmp_printf( FONT_SMALL, x_pos2, y_pos2,"[%X]%X", x, new_val); x_pos2 += 120; /* Extra space required */ if (x_pos2 > 550) { x_pos2 =0; y_pos2 += 16; } } else { if (y_pos1 > 240 - 16) continue; bmp_printf( FONT_SMALL, x_pos1, y_pos1,"[%X]%X", x, new_val); x_pos1 += 80; if (x_pos1 > 550) { x_pos1 =0; y_pos1 += 16; } } /********************************************* * move to next printout position on screen * *********************************************/ } /* end of for() */ /********************** * How many updates? * **********************/ bmp_printf( FONT_SMALL, 640, 32,"md=%X", max_diffs); bmp_printf( FONT_SMALL, 640, 48,"C0=%X", *(unsigned int *) ( LVMgr_struct + 0xC0) ); bmp_printf( FONT_SMALL, 640, 64,"C4=%X", *(unsigned int *) ( LVMgr_struct + 0xC4) ); } /* end of aj_dump_LVMgr() */