Fandom

Magic Lantern Firmware Wiki

500d/T1i Task Sequencers

328pages on
this wiki
Add New Page
Talk0 Share

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.

General Notes - By: CouttsEdit

These are my notes I have created while looking into all of the tasks created from DryOS on the Rebel T1i / 500d. This page will contain my findings related to task sequencers and calls to CreateSequencer.

A sequencer appears to create a message queue and task using a name passed in arg2. This may be used to create multiple related tasks at the same time, and manage their message queues and events using a single handler function.


CreateSequencerEdit

Located at 0xFF029C38 in v1.1.0 firmware of the 500d.

Here is my breakdown of the function, with some help from the arm-console.

  • arg0 - passed as arg1 to task_create
  • arg1 - passed as arg2 to task_create
  • arg2 - passed as arg0 to task_create
  • arg3 - stored at off_0x20 of AllocateMemory struct.
  • arg4 - in first debug message, this is the Num value. also stored at off_0x18


DryosDebugMsg(0x0, 0x3, "[SEQ] CreateSequencer (%s, Num = %d)", arg2, [SP beforebranch]);
AllocateMemory(0x24);

if (ret_AllocateMemory == 0)
    RETURN 0x5;

KernelDry_KerQueue.c__create_message_queue___R0.name__R1.size__maybe(arg2, 0xA);
ret_AllocateMemory->off_0xC = ret_KernelDry_KerQueue.c__create_message_queue___R0.name__R1.size__maybe

if NE((ret_KernelDry_KerQueue.c__create_message_queue___R0.name__R1.size__maybe_FF029418 & 0x1)):
    DryosDebugMsg(0x0, 0x16, '[SEQ ERROR] CreateMessageQueue (%#x)', ret_KernelDry_KerQueue.c__create_message_queue___R0.name__R1.size__maybe)
    FreeMemory(ret_AllocateMemory)
    return 5

*(ret_AllocateMemory->off_0x0) = 'Sequencer'
*(ret_AllocateMemory->off_0x4) = ret_AllocateMemory->off_0x10
*(ret_AllocateMemory->off_0x8) = "[SEQ] CreateSequencer (%s, Num = %d)"
*(ret_AllocateMemory->off_0xC) = ret_KernelDry_KerQueue.c__create_message_queue_R0.name__R1.size__maybe
*(ret_AllocateMemory->off_0x10) = 1
*(ret_AllocateMemory->off_0x14) = arg3
*(ret_AllocateMemory->off_0x18) = arg2
*(ret_AllocateMemory->off_0x1C) = 0
*(ret_AllocateMemory->off_0x20) = *(arg3)

task_create(arg2, arg0, arg1, 0xFF0292CC, ret_AllocateMemory)

if EQ((ret_task_create & 0x1)):
    *(ret_AllocateMemory->off_0x8) = ret_task_create
    return ret_AllocateMemory

DryosDebugMsg(0x0, 0x16, '[SEQ ERROR] CreateTaskClass (%#x)', ret_task_create)
KernelDry_KerQueue.c_or_AJ_guess_USB_CreateMessageQueue(ret_KernelDry_KerQueue.c__create_message_queue___R0.name__R1.size__maybe)
FreeMemory(ret_AllocateMemory)
return 5

How It's CalledEdit

In the 500d v1.1.0 firmware, it is called in 4 spots:

  • 0xFF013330 - CreateSequencer(0x19, 0x2800, "Startup", 0x19C0, 0x6);
  • 0xFF01FC08 - CreateSequencer(0x15, 0x1000, "Terminate", 0x1BE8, 0x3);
  • 0xFF01FD80 - CreateSequencer(0x15, 0x1000, "Terminate", 0x1BC4, 0x3);
  • 0xFF0200AC - CreateSequencer(0x11, 0x1000, "Terminate", 0x1C0C, 0x2);


task_createEdit

When CreateSequencer is called, one of the things it does is it creates a new task. It's called like this:

task_create(arg2, arg0, arg1, 0xFF0292CC, ret_AllocateMemory)

So it looks like anything that calls CreateSequencer will have the same task? Odd. Let's look at that task. This is the output straight from the console:

In [40]: dec SEQ_seqEventDispatch
found 5 code paths
code has loops => expect bad results
emulating code path 1 of 5
emulating code path 2 of 5
emulating code path 3 of 5
emulating code path 4 of 5
emulating code path 5 of 5

merging
* * * * 
rebuilding
*(-4 + sp0) = lr0
*(-8 + sp0) = unk_R4
*(-12 + sp0) = arg3
*(-16 + sp0) = arg2
if -arg0->off_0x18 < -arg0->off_0x1C /*CC*/:
    msg_queue_receive(arg0->off_0xC, -12 + sp0, 0x0, arg3) => ret_msg_queue_receive_FF0292E4
    if ret_msg_queue_receive_FF0292E4 == 0 /*EQ*/:
        !!! Stack not restored !!!
        !end
        if arg0->off_0x10 != 0 /*NE*/:
            *(-16 + sp0) = arg3
            DryosDebugMsg(0x0, 0x5, '[SEQ] seqEventDispatch (%s, %d)', arg0->off_0x4) => ret_DryosDebugMsg_FF029314
            j_IRQ_disable() => ret_j_IRQ_disable_FF029318
            arg0->off_0x1C = 1 + arg0->off_0x1C
            arg0->off_0x20 = *(12 + 12*arg0->off_0x1C + arg0->off_0x14)
            j_IRQ_restore() => ret_j_IRQ_restore_FF029338
            FUNC(*(4 + 12*arg3 + arg0->off_0x14))(*(4 + 12*arg3 + arg0->off_0x14), 0x0, 0x0, *(4 + 12*arg3 + arg0->off_0x14)) => ret_FUNC(*(4 + 12*arg3 + arg0->off_0x14))_FF02935C
        if arg0->off_0x10 == 0 /*EQ*/:
            DryosDebugMsg(0x0, 0x5, '[SEQ] seqEventDispatch (%s) : Canceled', arg0->off_0x4) => ret_DryosDebugMsg_FF029374
            DryosDebugMsg(0x0, 0x5, '[SEQ] seqEventDispatch (%s) : End', arg0->off_0x4) => ret_DryosDebugMsg_FF0293B0
            KernelDry_KerQueue.c_or_AJ_guess_USB_CreateMessageQueue(arg0->off_0xC) => ret_KernelDry_KerQueue.c_or_AJ_guess_USB_CreateMessageQueue_FF0293B8
            FreeMemory(arg0) => ret_FreeMemory_FF0293C0
            return ret_FreeMemory_FF0293C0
            !end
    if ret_msg_queue_receive_FF0292E4 != 0 /*NE*/:
        DryosDebugMsg(0x0, 0x16, '[SEQ ERROR] ReceiveMessageQueue (%#x)', ret_msg_queue_receive_FF0292E4) => ret_DryosDebugMsg_FF02938C
        if CS(-arg0->off_0x18 + arg0->off_0x1C):
            DryosDebugMsg(0x0, 0x5, '[SEQ] seqEventDispatch (%s) : End', arg0->off_0x4) => ret_DryosDebugMsg_FF0293B0
            KernelDry_KerQueue.c_or_AJ_guess_USB_CreateMessageQueue(arg0->off_0xC) => ret_KernelDry_KerQueue.c_or_AJ_guess_USB_CreateMessageQueue_FF0293B8
            FreeMemory(arg0) => ret_FreeMemory_FF0293C0
            return ret_FreeMemory_FF0293C0
        !!! Stack not restored !!!
        !end
if CS(-arg0->off_0x18 + arg0->off_0x1C):
    DryosDebugMsg(0x0, 0x5, '[SEQ] seqEventDispatch (%s) : End', arg0->off_0x4) => ret_DryosDebugMsg_FF0293B0
    KernelDry_KerQueue.c_or_AJ_guess_USB_CreateMessageQueue(arg0->off_0xC) => ret_KernelDry_KerQueue.c_or_AJ_guess_USB_CreateMessageQueue_FF0293B8
    FreeMemory(arg0) => ret_FreeMemory_FF0293C0
    return ret_FreeMemory_FF0293C0
    !end




Other Forms of SequencersEdit

In LV_Initialize - 0xFF033F84, there is a call to a function similar to CreateSequencer, for what appears to be a live view task (possibly). There is some kind of event system here. Here's the decompiler output for a backwards decompile to the call to this function, I have bolded the function we are looking into (this doesn't look to be very accurate, never trust the console completely***):

In [44]: bd 0xFF034030
*(-4 + sp0) = lr0
*(-8 + sp0) = unk_R11
*(-12 + sp0) = unk_R10
*(-16 + sp0) = unk_R9
*(-20 + sp0) = unk_R8
*(-24 + sp0) = unk_R7
*(-28 + sp0) = unk_R6
*(-32 + sp0) = unk_R5
*(-36 + sp0) = unk_R4
*(-40 + sp0) = arg3
*(-44 + sp0) = arg2
*(-48 + sp0) = arg1
*(-52 + sp0) = arg0
DryosDebugMsg(0x9b, 0x3, 'LV_Initialize %s', 'Mar 11 2009') => ret_DryosDebugMsg_FF033FA8
if *0x1D78 == 0 /*EQ*/:
    AllocateMemory(9956) => ret_AllocateMemory_FF033FC0
    if ret_AllocateMemory_FF033FC0 != 0 /*NE*/:
        ret_AllocateMemory_FF033FC0->off_0x8C = 1
        *(9776 + ret_AllocateMemory_FF033FC0) = 1185
        *(9792 + ret_AllocateMemory_FF033FC0) = 0
        *(9948 + ret_AllocateMemory_FF033FC0) = 1
        *(9796 + ret_AllocateMemory_FF033FC0) = HALFWORD(0)
        *(9784 + ret_AllocateMemory_FF033FC0) = -1
        *(ret_AllocateMemory_FF033FC0) = 'LiveViewMgr'
        *(-136 + sp0) = @sub_FF033F1C
        sub_FF1A6790('LiveViewMgr', arg1, 0xc00, 0xc8) => ret_sub_FF1A6790_FF034030
        !!! Stack not restored !!!
        !end
    if TRUE(ret_AllocateMemory_FF033FC0):
        *0x1D78 = ret_AllocateMemory_FF033FC0


Now this function decompiled:

In [45]: dec 0xFF1A6790
found 4 code paths
emulating code path 1 of 4
emulating code path 2 of 4
emulating code path 3 of 4
emulating code path 4 of 4

merging
* * * 
rebuilding
*(-4 + sp0) = lr0
*(-8 + sp0) = unk_R9
*(-12 + sp0) = unk_R8
*(-16 + sp0) = unk_R7
*(-20 + sp0) = unk_R6
*(-24 + sp0) = unk_R5
*(-28 + sp0) = unk_R4
*(-32 + sp0) = arg3
AllocateMemory(24) => ret_AllocateMemory_FF1A67AC
if ret_AllocateMemory_FF1A67AC == 0 /*EQ*/:
    return 5
*(ret_AllocateMemory_FF1A67AC) = 'TaskClass'
ret_AllocateMemory_FF1A67AC->off_0x4 = arg0
ret_AllocateMemory_FF1A67AC->off_0x8 = 1
ret_AllocateMemory_FF1A67AC->off_0x14 = arg4
KernelDry_KerQueue.c__create_message_queue___R0.name__R1.size__maybe(arg0, arg3) => ret_KernelDry_KerQueue.c__create_message_queue___R0.name__R1.size__maybe_FF1A67E0
ret_AllocateMemory_FF1A67AC->off_0x10 = ret_KernelDry_KerQueue.c__create_message_queue___R0.name__R1.size__maybe_FF1A67E0
if NE((ret_KernelDry_KerQueue.c__create_message_queue___R0.name__R1.size__maybe_FF1A67E0 & 0x1)):
    FreeMemory(ret_AllocateMemory_FF1A67AC) => ret_FreeMemory_FF1A67F4
    return 5
*(-32 + sp0) = ret_AllocateMemory_FF1A67AC
task_create(arg0, arg1, arg2, @sub_FF1A671C, ret_AllocateMemory_FF1A67AC)
ret_AllocateMemory_FF1A67AC->off_0xC = ret_task_create_FF1A6810
if EQ((ret_task_create_FF1A6810 & 0x1)):
    return ret_AllocateMemory_FF1A67AC
KernelDry_KerQueue.c_or_AJ_guess_USB_CreateMessageQueue(ret_KernelDry_KerQueue.c__create_message_queue___R0.name__R1.size__maybe_FF1A67E0) => ret_KernelDry_KerQueue.c_or_AJ_guess_USB_CreateMessageQueue_FF1A6828
FreeMemory(ret_AllocateMemory_FF1A67AC) => ret_FreeMemory_FF1A67F4
return 5
!end

In this function, task_create is called as follows (i traced the value of arg1 back to where LV_Initialize is called from):

task_create("LiveViewMgr", 0x11, 0xCC0, 0xFF1A671C, ret_AllocateMemory);

So, every function that calls this function (0xFF1A6790) will all use the same task function at 0xFF1A671C. There are quite a few callers. Here are their call locations, and the name of their task created:

  • 0xFF0261C4 -- EventMgr
  • 0xFF027110 -- FileCache
  • 0xFF029F80 -- RscMgr
  • 0xFF034030 -- LiveViewMgr
  • 0xFF035118 -- LVC_AE
  • 0xFF0355B0 -- LVC_AF
  • 0xFF035F1C -- LVC_DEV
  • 0xFF036A9C -- LVC_MD
  • 0xFF0387B0 -- ReDevelop
  • 0xFF03BFA8 -- Ceres
  • 0xFF040184 -- FileMgr
  • 0xFF04CC38 -- MovWriter
  • 0xFF04E598 -- MovieRecorder
  • 0xFF0594D8 -- PropMgr
  • 0xFF0668E4 -- DbgMgr
  • 0xFF0C4068 -- DpMgr
  • 0xFF0D9A1C -- DpImgEditMgr
  • 0xFF0E8460 -- LiveViewAngelMgr
  • 0xFF11F12C -- SdioDrv
  • 0xFF13C998 -- Mrk
  • 0xFF19F4C4 -- IPCTask
  • 0xFF19F6A8 -- IPCTask
  • 0xFF21934C -- SdioTsk
  • 0xFF22ED88 -- Decrypto

Now to take a look at the task function for all of these (at 0xFF1A671C):

The Task Function - located at 0xFF1A671CEdit

A C interpretation from Trammell Hudson (I have modified it slightly):

struct arg {
       uint32_t off_0x00
       uint32_t off_0x04;
       uint32_t enabled;   // off_0x08
       uint32_t off_0x0c;
       uint32_t off_0x10;
       void (*handler)(uint32_t, uint32_t, uint32_t, uint32_t); // off_0x14
};

void sub_FF1A671C( struct arg * arg )
{
       uint32_t x, y, z, w;
       while (arg->enabled)
       {
               int rc = sub_FF1A6690(arg, &x, &y, &z, &w);
               if (rc != 0)
                       continue;
               if (!arg->enabled)
                       break;
               arg->handler(x, y, z, w);
       }

       return 0;
}

This seems very accurate to me. The question though is where do x, y, z, and w come from?

Here everything broken down for our LiveViewMgr example, starting from LV_Initialize:

  • LV_Initialize calls sub_FF1A6790 (function that creates a msg_queue and task), the location of lvEventDispatch (sub_FF033F1C) is passed as arg4 to it.
  • after jumping to sub_FF1A6790 (function that creates a msg_queue and task), lvEventDispatch's location is stored at arg->handler.
  • msg_queue is created [haven't looked at that part yet]
  • return of msg_queue function is stored at arg->enabled
  • task is created
  • [now in task loop] sub_FF1A6690 (function that checks msg_queue) is called.
    • If it returns 0, then the value of arg->enabled is checked.
      • If arg->enabled is 0 as well, then the task ends.
      • If arg->enabled isn't 0, then arg->handler(x, y, z, w) is called.
    • If it doesn't return 0, then the value of arg->enabled is checked.
      • If arg->enabled is 0, then the task ends.
      • If arg->enabled isn't 0, then start the loop over, calling sub_FF1A6690 again.


sub_FF1A6690 (function that checks msg_queue) decompiled:

In [52]: dec FF1A6690
found 3 code paths
emulating code path 1 of 3
emulating code path 2 of 3
emulating code path 3 of 3

merging
* * 
rebuilding
*(-4 + sp0) = lr0
*(-8 + sp0) = unk_R9
*(-12 + sp0) = unk_R8
*(-16 + sp0) = unk_R7
*(-20 + sp0) = unk_R6
*(-24 + sp0) = unk_R5
*(-28 + sp0) = unk_R4
*(-32 + sp0) = arg3
if NE(12111470 + *(arg0)):
    return 7
*(-32 + sp0) = 0
msg_queue_receive(arg0->off_0x10, -32 + sp0, arg5, 'TaskClass') => ret_msg_queue_receive_FF1A66D0
if ret_msg_queue_receive_FF1A66D0 == 0 /*EQ*/:
    *(arg1) = *0x0
    *(arg2) = *0x4
    *(arg3) = *0x8
    *(arg4) = *0xC
    FreeMemory(0x0) => ret_FreeMemory_FF1A6710

return ret_msg_queue_receive_FF1A66D0
!end
==arg->handler()==

From our example with LiveViewMgr, arg->handler's value is lvEventDispatch (sub_FF033F1C). Here it is decompiled:

In [53]: dec FF033F1C
found 2 code paths
emulating code path 1 of 2
emulating code path 2 of 2

merging
* 
rebuilding
*(-4 + sp0) = lr0
*(-8 + sp0) = unk_R6
*(-12 + sp0) = unk_R5
*(-16 + sp0) = unk_R4
*(-20 + sp0) = arg3
*(-24 + sp0) = arg2
*(-24 + sp0) = arg3
sub_FF1A61D4((*0x1D78)->off_0xC, arg0, arg1, arg2) => ret_sub_FF1A61D4_FF033F48
if ret_sub_FF1A61D4_FF033F48 != 0 /*NE*/:
    (*0x1D78)->off_0xC = ret_sub_FF1A61D4_FF033F48
    return ret_sub_FF1A61D4_FF033F48
sub_FF1A6390((*0x1D78)->off_0xC) => ret_sub_FF1A6390_FF033F64
*(-24 + sp0) = arg1
*(-20 + sp0) = arg2
DryosDebugMsg(0x98, 0x6, 'lvEventDispatch : Current = %d, dwEventID = %d, dwParam = %#x', ret_sub_FF1A6390_FF033F64) => ret_DryosDebugMsg_FF033F7C
return ret_DryosDebugMsg_FF033F7C
!end


sub_FF1A61D4 and sub_FF1A6390 are related to state objects:

In [54]: dec FF1A61D4
found 2 code paths
emulating code path 1 of 2
emulating code path 2 of 2

merging
* 
rebuilding
*(-4 + sp0) = lr0
*(-8 + sp0) = unk_R5
*(-12 + sp0) = unk_R4
*(-16 + sp0) = arg3
REGWRITE(LR, arg3)
if ():
    return 7
*(-16 + sp0) = arg4
FUNC(arg0->off_0xC)(arg0, arg1, arg2, arg3) => ret_FUNC(arg0->off_0xC)_FF1A6204
return ret_MEM(12 + arg0)_FF1A6204
!end
In [64]: dec  sub_FF1A6390
found 2 code paths
emulating code path 1 of 2
emulating code path 2 of 2

merging
* 
rebuilding
if *(arg0) == 'StateObject' /*EQ*/:
    return arg0->off_0x1C
return -1
!end


I'm done digging for now. As I finsih this up, I have been working on this for 14 hours straight now, I can't think about it much more.

Also on Fandom

Random Wiki