-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathinit.c
405 lines (331 loc) · 9.39 KB
/
init.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
/** \file
* Code to run on the 5D once it has been relocated.
*
* This has been updated to work with the 2.0.8 firmware.
*/
/*
* Copyright (C) 2009 Trammell Hudson <[email protected]>
*
* 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"
/** If CONFIG_EARLY_PORT is defined, only a few things will be enabled */
#undef CONFIG_EARLY_PORT
/** These are called when new tasks are created */
void my_task_dispatch_hook( struct context ** );
void my_init_task(void);
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) )
/** 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
__attribute__((noreturn,noinline,naked))
copy_and_restart( void )
{
zero_bss();
// Copy the firmware to somewhere in memory
// bss ends at 0x47750, so we'll use 0x50000
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() (0xff812a98) make this change to
* return to our code before calling cstart().
* This should be a "BL cstart" instruction.
*/
INSTR( 0xFF812AE8 ) = RET_INSTR;
/*
* in cstart() (0xff810894) make these changes:
*/
// Reserve memory after the BSS for our application
// should be a pointer to 0x4d458 or thereabouts
INSTR( 0xFF81093C ) = (uintptr_t) _bss_end;
// Fix the calls to bzero32() and create_init_task()
FIXUP_BRANCH( 0xFF8108A4, bzero32 );
FIXUP_BRANCH( 0xFF81092C, create_init_task );
// Set our init task to run instead of the firmware one
INSTR( 0xFF810948 ) = (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.
*/
#ifndef CONFIG_EARLY_PORT
// Install our task creation hooks
task_dispatch_hook = my_task_dispatch_hook;
#endif
// 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)
;
}
struct config * global_config;
#ifndef CONFIG_EARLY_PORT
void
null_task( void )
{
DebugMsg( DM_SYS, 3, "%s created (and exiting)", __func__ );
return;
}
/**
* Called by DryOS when it is dispatching (or creating?)
* a new task.
*/
void
my_task_dispatch_hook(
struct context ** context
)
{
if( !context )
return;
// Determine the task address
struct task * task = (struct task*)
( ((uint32_t)context) - offsetof(struct task, context) );
// Do nothing unless a new task is starting via the trampoile
if( task->context->pc != (uint32_t) task_trampoline )
return;
thunk entry = (thunk) task->entry;
// Search the task_mappings array for a matching entry point
extern struct task_mapping _task_overrides_start[];
extern struct task_mapping _task_overrides_end[];
const struct task_mapping * mapping = _task_overrides_start;
for( ; mapping < _task_overrides_end ; mapping++ )
{
thunk original_entry = mapping->orig;
if( original_entry != entry )
continue;
/* -- can't call debugmsg from this context */
#if 0
DebugMsg( DM_SYS, 3, "***** Replacing task %x with %x",
original_entry,
mapping->replacement
);
#endif
task->entry = mapping->replacement;
break;
}
}
/** First task after a fresh rebuild.
*
* Try to dump the debug log after ten seconds.
* This requires the create_task(), dmstart(), msleep() and dumpf()
* routines to have been found.
*/
void
my_dump_task( void )
{
dmstart();
msleep( 10000 );
dispcheck();
dumpf();
dmstop();
}
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();
}
init_funcs_done = 1;
}
#endif // !CONFIG_EARLY_PORT
static void nop( void ) { }
void menu_init( void ) __attribute__((weak,alias("nop")));
void debug_init( void ) __attribute__((weak,alias("nop")));
#ifndef CONFIG_EARLY_PORT
volatile int shutdown_requested;
static void *
prop_startup_handler(
unsigned property,
void * token,
void * arg,
unsigned len
)
{
uint32_t * const buf = arg;
if (buf[0] != 0xFF)
{
// Time to shutdown. Let everyone else know
bmp_printf( FONT_SMALL, 0, 40, "shutdown requested");
shutdown_requested = 1;
return prop_cleanup( token, property );
}
// We are finally ready to startup! Bring up the monitor
call("TurnOnDisplay");
menu_init();
debug_init();
// Parse our config file
const char * config_filename = "A:/magiclantern.cfg";
global_config = config_parse_file( config_filename );
bmp_printf( FONT_SMALL, 0, 40,
"Magic Lantern version %s (%s)\n"
"Built on %s by %s\n",
build_version,
build_id,
build_date,
build_user
);
bmp_printf( FONT_SMALL, 0, 64,
"Config file %s: %s arg=%d %d %d %d",
config_filename,
global_config ? "YES" : "NO",
(int) buf[0],
(int) buf[1],
(int) buf[2],
(int) buf[3]
);
init_funcs_done = 0;
//task_create( "init_func", 0x1f, 0x1000, call_init_funcs, 0 );
//while( !init_funcs_done )
//msleep(10);
call_init_funcs( 0 );
// Create all of our auto-create tasks
extern struct task_create _tasks_start[];
extern struct task_create _tasks_end[];
struct task_create * task = _tasks_start;
unsigned y = 64;
for( ; task < _tasks_end ; task++ )
{
DebugMsg( DM_MAGIC, 3,
"Creating task %s(%d) pri=%02x flags=%08x",
task->name,
task->arg,
task->priority,
task->flags
);
bmp_printf( FONT_SMALL, 0, y += 12,
"Starting %s pri=%02x",
task->name,
task->priority
);
task_create(
task->name,
task->priority,
task->flags,
task->entry,
task->arg
);
}
DebugMsg( DM_MAGIC, 3, "magic lantern init done" );
return prop_cleanup( token, property );
}
static struct prop_handler prop_startup = {
.handler = prop_startup_handler,
.property = PROP_TERMINATE_SHUT_REQ,
};
#endif // !CONFIG_EARLY_PORT
/** 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.
*/
void
my_init_task(void)
{
// Call their init task
init_task();
#ifndef CONFIG_EARLY_PORT
// Overwrite the PTPCOM message
dm_names[ DM_MAGIC ] = "[MAGIC] ";
dmstart();
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
);
#endif
// 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] = '-';
additional_version[4] = build_version[0];
additional_version[5] = build_version[1];
additional_version[6] = build_version[2];
additional_version[7] = build_version[3];
additional_version[8] = build_version[4];
additional_version[9] = '\0';
#ifndef CONFIG_EARLY_PORT
// Once we are past the early port phase, we can register
// our shutdown/startup property handler
msleep( 1000 );
prop_handler_init( &prop_startup );
#endif
}