Magic Lantern Firmware Wiki
Advertisement

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
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() */
Advertisement