installer.c
/** \file
* This is similar to boot-hack, but simplified. It only does the first-time install (bootflag setup).
*/
/*
* Copyright (C) 2009 Trammell Hudson <hudson+ml@osresearch.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "dryos.h"
#include "config.h"
#include "version.h"
#include "bmp.h"
#include "menu.h"
#include "version.h"
#include "property.h"
#include "consts.h"
void NotifyBox(int timeout, char* fmt, ...)
{
beep();
static char notify_box_msg[100];
va_list ap;
va_start( ap, fmt );
vsnprintf( notify_box_msg, sizeof(notify_box_msg), fmt, ap );
va_end( ap );
bmp_printf(FONT_LARGE, 0, 0, "%s", notify_box_msg);
}
/** These are called when new tasks are created */
int my_init_task(int a, int b, int c, int d);
void my_bzero( uint8_t * base, uint32_t size );
/** This just goes into the bss */
#define RELOCSIZE 0x10000
static uint8_t _reloc[ RELOCSIZE ];
#define RELOCADDR ((uintptr_t) _reloc)
/** Translate a firmware address into a relocated address */
#define INSTR( addr ) ( *(uint32_t*)( (addr) - ROMBASEADDR + RELOCADDR ) )
/** Fix a branch instruction in the relocated firmware image */
#define FIXUP_BRANCH( rom_addr, dest_addr ) \
INSTR( rom_addr ) = BL_INSTR( &INSTR( rom_addr ), (dest_addr) )
/** Was this an autoboot or firmware file load? */
int autoboot_loaded;
/** Specified by the linker */
extern uint32_t _bss_start[], _bss_end[];
static inline void
zero_bss( void )
{
uint32_t *bss = _bss_start;
while( bss < _bss_end )
*(bss++) = 0;
}
void card_led_on() { cli_save(); *(int*)CARD_LED_ADDRESS |= 2; sei_restore(); }
void card_led_off() { cli_save(); *(int*)CARD_LED_ADDRESS &= ~2; sei_restore(); }
void card_led_blink(int times, int delay_on, int delay_off)
{
int i;
for (i = 0; i < times; i++)
{
card_led_on();
Msleep(delay_on);
card_led_off();
Msleep(delay_off);
}
}
void
__attribute__((noreturn,noinline,naked))
copy_and_restart( int offset )
{
zero_bss();
// Set the flag if this was an autoboot load
autoboot_loaded = (offset == 0);
// Copy the firmware to somewhere safe in memory
const uint8_t * const firmware_start = (void*) ROMBASEADDR;
const uint32_t firmware_len = RELOCSIZE;
uint32_t * const new_image = (void*) RELOCADDR;
blob_memcpy( new_image, firmware_start, firmware_start + firmware_len );
/*
* in entry2() (0xff010134) make this change to
* return to our code before calling cstart().
* This should be a "BL cstart" instruction.
*/
INSTR( HIJACK_INSTR_BL_CSTART ) = RET_INSTR;
/*
* in cstart() (0xff010ff4) make these changes:
* calls bzero(), then loads bs_end and calls
* create_init_task
*/
// Reserve memory after the BSS for our application
INSTR( HIJACK_INSTR_BSS_END ) = (uintptr_t) _bss_end;
// Fix the calls to bzero32() and create_init_task()
FIXUP_BRANCH( HIJACK_FIXBR_BZERO32, bzero32 );
FIXUP_BRANCH( HIJACK_FIXBR_CREATE_ITASK, create_init_task );
// Set our init task to run instead of the firmware one
INSTR( HIJACK_INSTR_MY_ITASK ) = (uint32_t) my_init_task;
// Make sure that our self-modifying code clears the cache
clean_d_cache();
flush_caches();
// We enter after the signature, avoiding the
// relocation jump that is at the head of the data
thunk reloc_entry = (thunk)( RELOCADDR + 0xC );
reloc_entry();
/*
* We're back!
* The RAM copy of the firmware startup has:
* 1. Poked the DMA engine with what ever it does
* 2. Copied the rw_data segment to 0x1900 through 0x20740
* 3. Zeroed the BSS from 0x20740 through 0x47550
* 4. Copied the interrupt handlers to 0x0
* 5. Copied irq 4 to 0x480.
* 6. Installed the stack pointers for CPSR mode D2 and D3
* (we are still in D3, with a %sp of 0x1000)
* 7. Returned to us.
*
* Now is our chance to fix any data segment things, or
* install our own handlers.
*/
// This will jump into the RAM version of the firmware,
// but the last branch instruction at the end of this
// has been modified to jump into the ROM version
// instead.
void (*ram_cstart)(void) = (void*) &INSTR( cstart );
ram_cstart();
// Unreachable
while(1)
;
}
int autoexec_ok; // true if autoexec.bin was found
int fonts_ok; // true if fonts.dat was found
int old_shooting_mode; // to detect when mode dial changes
int bootflag_written = 0;
// print a message and redraw it continuously (so it won't be erased by camera firmware)
#define PERSISTENT_PRINTF(times, font, x, y, msg, ...) { int X = times; while(X--) { bmp_printf(font, x, y, msg, ## __VA_ARGS__); Msleep(100); } }
#define UILOCK_EVERYTHING_EXCEPT_POWEROFF_AND_MODEDIAL 0x4100014f
#define UILOCK_EVERYTHING 0x4100017f
void ui_lock(int x)
{
int unlocked = 0x41000000;
prop_request_change(PROP_ICU_UILOCK, &unlocked, 4);
Msleep(200);
prop_request_change(PROP_ICU_UILOCK, &x, 4);
Msleep(200);
}
void beep()
{
call("StartPlayWaveData");
Msleep(1000);
call("StopPlayWaveData");
}
void fake_simple_button(int bgmt_code)
{
GUI_Control(bgmt_code, 0, 0, 0);
}
void install_task()
{
//~ PERSISTENT_PRINTF(30, FONT_LARGE, 50, 50, "Install task starting...");
while (sensor_cleaning) Msleep(200);
//~ PERSISTENT_PRINTF(30, FONT_LARGE, 50, 50, "Sensor cleaning done... ");
Msleep(200);
#ifdef CONFIG_600D
#define BGMT_DISP BGMT_INFO
#endif
//~ PERSISTENT_PRINTF(30, FONT_LARGE, 50, 50, "TFT status: %d ", tft_status);
if (tft_status || gui_state != GUISTATE_IDLE) { fake_simple_button(BGMT_DISP); Msleep(500); }
if (tft_status || gui_state != GUISTATE_IDLE) { fake_simple_button(BGMT_DISP); Msleep(500); }
if (tft_status || gui_state != GUISTATE_IDLE) { fake_simple_button(BGMT_DISP); Msleep(500); }
if (tft_status || gui_state != GUISTATE_IDLE) { fake_simple_button(BGMT_DISP); Msleep(500); }
if (tft_status || gui_state != GUISTATE_IDLE) { SW1(1,100); SW1(0,100); Msleep(500); }
#ifdef CONFIG_50D
if (tft_status) { fake_simple_button(BGMT_DISP); Msleep(500); }
if (tft_status) { fake_simple_button(BGMT_DISP); Msleep(500); }
if (tft_status) { fake_simple_button(BGMT_DISP); Msleep(500); }
if (tft_status)
#else
if (tft_status || gui_state != GUISTATE_IDLE)
#endif
{
PERSISTENT_PRINTF(30, FONT_LARGE, 50, 50, "TFT status error... ");
card_led_blink(10, 10, 90);
card_led_blink(10, 90, 10);
card_led_blink(10, 10, 90);
card_led_blink(10, 90, 10);
card_led_blink(10, 10, 90);
card_led_blink(10, 90, 10);
beep();
return; // display off, can't install
}
Msleep(500);
//~ PERSISTENT_PRINTF(30, FONT_LARGE, 50, 50, "TFT status OK! ");
canon_gui_disable();
ui_lock(UILOCK_EVERYTHING);
//~ PERSISTENT_PRINTF(30, FONT_LARGE, 50, 50, "UI locked! ");
autoexec_ok = check_autoexec();
fonts_ok = check_fonts();
//~ PERSISTENT_PRINTF(30, FONT_LARGE, 50, 50, "Autoexec & fonts checked");
initial_install();
old_shooting_mode = shooting_mode;
//~ PERSISTENT_PRINTF(30, FONT_LARGE, 50, 50, "Initial install DONE!!! ");
ui_lock(UILOCK_EVERYTHING_EXCEPT_POWEROFF_AND_MODEDIAL);
//~ PERSISTENT_PRINTF(30, FONT_LARGE, 50, 50, "Going interactive.......");
int k = 0;
for (;;k++)
{
while (sensor_cleaning) msleep(100);
check_install();
if (shooting_mode != old_shooting_mode)
{
bootflag_toggle();
}
old_shooting_mode = shooting_mode;
Msleep(100);
}
}
void redraw() { clrscr(); }
static volatile int init_funcs_done;
static void
call_init_funcs( void * priv )
{
// Call all of the init functions
extern struct task_create _init_funcs_start[];
extern struct task_create _init_funcs_end[];
struct task_create * init_func = _init_funcs_start;
for( ; init_func < _init_funcs_end ; init_func++ )
{
DebugMsg( DM_MAGIC, 3,
"Calling init_func %s (%x)",
init_func->name,
(unsigned) init_func->entry
);
thunk entry = (thunk) init_func->entry;
entry();
}
}
// this Msleep works with display off too
void Msleep(int ms)
{
int i;
for (i = 0; i < ms/100; i++)
{
msleep(100);
call("DisablePowerSave"); // trick from AJ_MREQ_ISR
call("EnablePowerSave"); // to prevent camera for entering "deep sleep"
}
}
/** Initial task setup.
*
* This is called instead of the task at 0xFF811DBC.
* It does all of the stuff to bring up the debug manager,
* the terminal drivers, stdio, stdlib and armlib.
*/
int my_init_task(int a, int b, int c, int d)
{
// Call their init task
int ans = init_task(a,b,c,d);
// Overwrite the PTPCOM message
dm_names[ DM_MAGIC ] = "[MAGIC] ";
//~ dmstart(); // already called by firmware?
DebugMsg( DM_MAGIC, 3, "Magic Lantern %s (%s)",
build_version,
build_id
);
DebugMsg( DM_MAGIC, 3, "Built on %s by %s",
build_date,
build_user
);
// Re-write the version string.
// Don't use strcpy() so that this can be done
// before strcpy() or memcpy() are located.
extern char additional_version[];
additional_version[0] = '-';
additional_version[1] = 'm';
additional_version[2] = 'l';
additional_version[3] = '\0';
Msleep( 2000 );
call_init_funcs(0);
Msleep(1000);
task_create("install_task", 0x1b, 0, install_task, 0);
return ans;
}
/** Shadow copy of the NVRAM boot flags stored at 0xF8000000 */
#define NVRAM_BOOTFLAGS ((void*) 0xF8000000)
struct boot_flags
{
uint32_t firmware; // 0x00
uint32_t bootdisk; // 0x04
uint32_t ram_exe; // 0x08
uint32_t update; // 0x0c
uint32_t flag_0x10;
uint32_t flag_0x14;
uint32_t flag_0x18;
uint32_t flag_0x1c;
};
static struct boot_flags * const boot_flags = NVRAM_BOOTFLAGS;;
void SW1(int v, int wait)
{
prop_request_change(PROP_REMOTE_SW1, &v, 2);
Msleep(wait);
}
void SW2(int v, int wait)
{
prop_request_change(PROP_REMOTE_SW2, &v, 2);
Msleep(wait);
}
/** Perform an initial install and configuration */
void
initial_install(void)
{
bmp_fill(0, 0, 0, 720, 480);
int y = 0;
bmp_printf(FONT_LARGE, 0, y+=30, "Magic Lantern install");
if (!autoexec_ok)
{
bmp_printf(FONT_LARGE, 0, y+=30, "AUTOEXEC.BIN not found!");
msleep(5000);
return;
}
if (!fonts_ok)
{
bmp_printf(FONT_LARGE, 0, y+=30, "FONTS.DAT not found!");
msleep(5000);
return;
}
if (!boot_flags->bootdisk )
{
if (!lv && !sensor_cleaning && shooting_mode != SHOOTMODE_MOVIE)
{
bmp_printf(FONT_LARGE, 0, y+=30, "Setting boot flag");
call( "EnableBootDisk" );
}
else
{
bmp_printf(FONT_LARGE, 0, y+=30, "Did not enable boot flag.");
msleep(5000);
return;
}
}
bmp_printf(FONT_LARGE, 0, y+=30, "Making card bootable...");
bootflag_written = bootflag_write_bootblock();
if (!bootflag_written)
{
bmp_printf(FONT_LARGE, 0, y, "You need to run EOSCard/MacBoot.");
msleep(5000);
}
//~ bmp_printf(FONT_LARGE, 0, y+=30, "Writing boot log");
//~ dumpf();
bmp_printf(FONT_LARGE, 0, y+=30, "Done!");
Msleep(1000);
}
void bootflag_toggle( void * priv )
{
if( boot_flags->firmware )
{
firmware_fix();
return;
}
clrscr();
ui_lock(UILOCK_EVERYTHING);
clrscr();
int i;
if( boot_flags->bootdisk )
{
for (i = 0; i < 10; i++)
{
bmp_printf(FONT_LARGE, 50, 100, "DisableBootDisk");
card_led_blink(1, 50, 50);
}
if (!lv && !sensor_cleaning && shooting_mode != SHOOTMODE_MOVIE)
call( "DisableBootDisk" ); // in movie mode, it causes ERR80 and then asks for a firmware update
}
else
{
for (i = 0; i < 10; i++)
{
bmp_printf(FONT_LARGE, 50, 100, "EnableBootDisk");
card_led_blink(1, 50, 50);
}
if (!lv && !sensor_cleaning && shooting_mode != SHOOTMODE_MOVIE)
call( "EnableBootDisk" );
}
card_led_blink(5, 100, 100);
ui_lock(UILOCK_EVERYTHING_EXCEPT_POWEROFF_AND_MODEDIAL);
}
void firmware_fix( void * priv )
{
clrscr();
ui_lock(UILOCK_EVERYTHING);
clrscr();
int i;
if( boot_flags->firmware )
{
for (i = 0; i < 10; i++)
{
bmp_printf(FONT_LARGE, 50, 100, "EnableMainFirm");
card_led_blink(1, 50, 50);
}
if (!lv && !sensor_cleaning && shooting_mode != SHOOTMODE_MOVIE)
call( "EnableMainFirm" ); // in movie mode, it causes ERR80 and then asks for a firmware update
}
card_led_blink(5, 100, 100);
ui_lock(UILOCK_EVERYTHING_EXCEPT_POWEROFF_AND_MODEDIAL);
}
// check if autoexec.bin is present on the card
int check_autoexec()
{
FILE * f = FIO_Open(CARD_DRIVE "AUTOEXEC.BIN", 0);
if (f != (void*) -1)
{
FIO_CloseFile(f);
return 1;
}
return 0;
}
// check if fonts.dat is present on the card
int check_fonts()
{
FILE * f = FIO_Open(CARD_DRIVE "FONTS.DAT", 0);
if (f != (void*) -1)
{
FIO_CloseFile(f);
return 1;
}
return 0;
}
// check ML installation and print a message
void check_install()
{
//~ Msleep(1);
if (boot_flags->firmware)
{
bmp_printf(FONT(FONT_LARGE, COLOR_RED, 0), 0, 0,
" MAIN_FIRMWARE flag is DISABLED! \n"
" \n"
" This was probably caused by a \n"
" failed install process. \n"
" \n"
" Camera may work with Magic Lantern,\n"
" but it will ask for a firmware \n"
" update as soon as you insert a \n"
" formatted card. \n"
" \n"
" To fix this (at your own risk!): \n"
" a) Turn the mode dial (P/Tv/Av/M) \n"
" (ML will try to fix this) \n"
" b) Reinstall Canon firmware. \n"
" \n"
);
}
else if( boot_flags->bootdisk )
{
if (autoexec_ok)
{
if (fonts_ok)
{
bmp_printf(FONT(FONT_LARGE, COLOR_GREEN1, 0), 0, 0,
" ********************************** \n"
" * SUCCESS! * \n"
" ********************************** \n"
" \n"
" BOOTDISK flag is ENABLED. \n"
" AUTOEXEC.BIN found. \n"
" \n"
" Magic Lantern is installed. \n"
" You may now restart your camera. \n"
"%s"
" \n"
" To disable the BOOTDISK flag, \n"
" change the shooting mode from the \n"
" mode dial (P/Tv/Av/M). \n"
" \n",
bootflag_written ?
" \n" :
" DON'T FORGET to make card bootable!\n"
);
}
else
{
bmp_printf(FONT(FONT_LARGE, COLOR_YELLOW, 0), 0, 0,
" \n"
" BOOTDISK flag is ENABLED. \n"
" AUTOEXEC.BIN found. \n"
" \n"
" !!! FONTS.DAT NOT FOUND !!! \n"
" \n"
" Please copy ALL ML files on your \n"
" SD card. They only take a few MB. \n"
" \n"
" You may now turn off your camera. \n"
" \n"
" To disable the BOOTDISK flag, \n"
" change the shooting mode from the \n"
" mode dial (P/Tv/Av/M). \n"
" \n"
);
}
}
else
{
bmp_printf(FONT(FONT_LARGE, COLOR_RED, 0), 0, 0,
" \n"
" BOOTDISK flag is ENABLED. \n"
" \n"
" !!! AUTOEXEC.BIN NOT FOUND !!! \n"
" \n"
" Remove battery and card \n"
" and copy AUTOEXEC.BIN, \n"
" otherwise camera will not boot! \n"
" \n"
" \n"
" \n"
" To disable the BOOTDISK flag, \n"
" change the shooting mode from the \n"
" mode dial (P/Tv/Av/M). \n"
" \n"
);
}
}
else
{
bmp_printf(FONT(FONT_LARGE, COLOR_WHITE, 0), 0, 0,
" \n"
" BOOTDISK flag is DISABLED. \n"
" \n"
" Magic Lantern is NOT installed. \n"
" You may now restart your camera. \n"
" \n"
" After reboot, clear all the \n"
" settings and custom functions \n"
" to complete the uninstallation. \n"
" \n"
" \n"
" To enable the BOOTDISK flag, \n"
" change the shooting mode from the \n"
" mode dial (P/Tv/Av/M). \n"
" \n"
);
}
bmp_printf( FONT_SMALL,
620,
430,
"Firmware %d\n"
"Bootdisk %d\n"
"RAM_EXE %d\n"
"Update %d\n",
boot_flags->firmware,
boot_flags->bootdisk,
boot_flags->ram_exe,
boot_flags->update
);
}
// dummy definitions for bmp.c
int ext_monitor_hdmi = 0;
int ext_monitor_rca = 0;
int hdmi_code = 0;
int lv = 0;
int lv_paused = 0;
void bvram_mirror_init(){};