📄 redboot_linux_exec.c
字号:
struct tag_cmdline cmdline;
/*
* Acorn specific
*/
struct tag_acorn acorn;
/*
* DC21285 specific
*/
struct tag_memclk memclk;
} u;
};
// End of inclusion from <asm-arm/setup.h>
//=========================================================================
// Default memory layout - can be overridden by platform, typically in
// <cyg/hal/plf_io.h>
#ifndef CYGHWR_REDBOOT_LINUX_ATAG_MEM
#define CYGHWR_REDBOOT_LINUX_ATAG_MEM(_p_) \
CYG_MACRO_START \
/* Next ATAG_MEM. */ \
_p_->hdr.size = (sizeof(struct tag_mem32) + sizeof(struct tag_header))/sizeof(long); \
_p_->hdr.tag = ATAG_MEM; \
/* Round up so there's only one bit set in the memory size. \
* Don't double it if it's already a power of two, though. \
*/ \
_p_->u.mem.size = 1<<hal_msbindex(CYGMEM_REGION_ram_SIZE); \
if (_p_->u.mem.size < CYGMEM_REGION_ram_SIZE) \
_p_->u.mem.size <<= 1; \
_p_->u.mem.start = CYGARC_PHYSICAL_ADDRESS(CYGMEM_REGION_ram); \
CYG_MACRO_END
#endif
// Round up a quantity to a longword (32 bit) length
#define ROUNDUP(n) (((n)+3)&~3)
static void
do_exec(int argc, char *argv[])
{
unsigned long entry;
unsigned long target;
unsigned long oldints;
bool wait_time_set;
int wait_time, res, num_opts;
bool base_addr_set, length_set, cmd_line_set;
bool ramdisk_addr_set, ramdisk_size_set;
unsigned long base_addr, length;
unsigned long ramdisk_addr, ramdisk_size;
struct option_info opts[7];
char line[8];
char *cmd_line;
struct tag *params = (struct tag *)CYGHWR_REDBOOT_ARM_LINUX_TAGS_ADDRESS;
#ifdef CYGHWR_REDBOOT_LINUX_EXEC_X_SWITCH
bool swap_endian;
extern char __xtramp_start__[], __xtramp_end__[];
#endif
extern char __tramp_start__[], __tramp_end__[];
// Check to see if a valid image has been loaded
if (entry_address == (unsigned long)NO_MEMORY) {
diag_printf("Can't execute Linux - invalid entry address\n");
return;
}
// Default physical entry point for Linux is kernel base.
entry = (unsigned long)CYGHWR_REDBOOT_ARM_LINUX_EXEC_ADDRESS;
target = (unsigned long)CYGHWR_REDBOOT_ARM_LINUX_EXEC_ADDRESS;
base_addr = load_address;
length = load_address_end - load_address;
// Round length up to the next quad word
length = (length + 3) & ~0x3;
ramdisk_size = 4096*1024;
init_opts(&opts[0], 'w', true, OPTION_ARG_TYPE_NUM,
(void **)&wait_time, (bool *)&wait_time_set, "wait timeout");
init_opts(&opts[1], 'b', true, OPTION_ARG_TYPE_NUM,
(void **)&base_addr, (bool *)&base_addr_set, "base address");
init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM,
(void **)&length, (bool *)&length_set, "length");
init_opts(&opts[3], 'c', true, OPTION_ARG_TYPE_STR,
(void **)&cmd_line, (bool *)&cmd_line_set, "kernel command line");
init_opts(&opts[4], 'r', true, OPTION_ARG_TYPE_NUM,
(void **)&ramdisk_addr, (bool *)&ramdisk_addr_set, "ramdisk_addr");
init_opts(&opts[5], 's', true, OPTION_ARG_TYPE_NUM,
(void **)&ramdisk_size, (bool *)&ramdisk_size_set, "ramdisk_size");
init_opts(&opts[6], 't', true, OPTION_ARG_TYPE_NUM,
&target, 0, "[physical] target address");
num_opts = 7;
#ifdef CYGHWR_REDBOOT_LINUX_EXEC_X_SWITCH
init_opts(&opts[num_opts], 'x', false, OPTION_ARG_TYPE_FLG,
(void **)&swap_endian, 0, "swap endianess");
++num_opts;
#endif
if (!scan_opts(argc, argv, 1, opts, num_opts, (void *)&entry, OPTION_ARG_TYPE_NUM, "[physical] starting address"))
{
return;
}
// Set up parameters to pass to kernel
// CORE tag must be present & first
params->hdr.size = (sizeof(struct tag_core) + sizeof(struct tag_header))/sizeof(long);
params->hdr.tag = ATAG_CORE;
params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;
params = (struct tag *)((long *)params + params->hdr.size);
// Fill in the details of the memory layout
CYGHWR_REDBOOT_LINUX_ATAG_MEM(params);
params = (struct tag *)((long *)params + params->hdr.size);
if (ramdisk_addr_set) {
params->hdr.size = (sizeof(struct tag_initrd) + sizeof(struct tag_header))/sizeof(long);
params->hdr.tag = ATAG_INITRD2;
params->u.initrd.start = CYGARC_PHYSICAL_ADDRESS(ramdisk_addr);
params->u.initrd.size = ramdisk_size;
params = (struct tag *)((long *)params + params->hdr.size);
}
if (cmd_line_set) {
params->hdr.size = (ROUNDUP(strlen(cmd_line)) + sizeof(struct tag_header))/sizeof(long);
params->hdr.tag = ATAG_CMDLINE;
strcpy(params->u.cmdline.cmdline, cmd_line);
params = (struct tag *)((long *)params + params->hdr.size);
}
// Mark end of parameter list
params->hdr.size = 0;
params->hdr.tag = ATAG_NONE;
if (wait_time_set) {
int script_timeout_ms = wait_time * 1000;
#ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
unsigned char *hold_script = script;
script = (unsigned char *)0;
#endif
diag_printf("About to start execution of image at %p, entry point %p - abort with ^C within %d seconds\n",
(void *)target, (void *)entry, wait_time);
while (script_timeout_ms >= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT) {
res = _rb_gets(line, sizeof(line), CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT);
if (res == _GETS_CTRLC) {
#ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
script = hold_script; // Re-enable script
#endif
return;
}
script_timeout_ms -= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT;
}
}
if (!base_addr_set) {
if ((base_addr == 0) || (length == 0)) {
// Probably not valid - don't try it
diag_printf("Base address unknown - use \"-b\" option\n");
return;
}
diag_printf("Using base address %p and length %p\n",
(void*)base_addr, (void*)length);
} else if (base_addr_set && !length_set) {
diag_printf("Length required for non-standard base address\n");
return;
}
#ifdef CYGPKG_IO_ETH_DRIVERS
eth_drv_stop();
#endif
HAL_DISABLE_INTERRUPTS(oldints);
HAL_DCACHE_SYNC();
HAL_ICACHE_DISABLE();
HAL_DCACHE_DISABLE();
HAL_DCACHE_SYNC();
HAL_ICACHE_INVALIDATE_ALL();
HAL_DCACHE_INVALIDATE_ALL();
// Tricky code. We are currently running with the MMU on and the
// memory map possibly convoluted from 1-1. The trampoline code
// between labels __tramp_start__ and __tramp_end__ must be copied
// to RAM and then executed at the non-mapped address.
//
// This magic was created in order to be able to execute standard
// Linux kernels with as little change/perturberance as possible.
#ifdef CYGHWR_REDBOOT_LINUX_EXEC_X_SWITCH
if (swap_endian) {
// copy the trampline code
memcpy((char *)CYGHWR_REDBOOT_ARM_TRAMPOLINE_ADDRESS,
__xtramp_start__,
__xtramp_end__ - __xtramp_start__);
asm volatile (
CYGARC_HAL_MMU_OFF_X(%5)
"__xtramp_start__:\n"
" cmp %1,%4;\n" // Default kernel load address. Relocate
" beq 2f;\n" // kernel image there if necessary, and
" cmp %2,#0;\n" // if size is non-zero
" beq 2f;\n"
"1:\n"
" ldr r0,[%1],#4;\n"
" eor %5, r0, r0, ror #16;\n"
" bic %5, %5, #0x00ff0000;\n"
" mov r0, r0, ror #8;\n"
" eor r0, r0, %5, lsr #8;\n"
" str r0,[%4],#4;\n"
" subs %2,%2,#4;\n"
" bne 1b;\n"
"2:\n"
" mov r0,#0;\n" // Set board type
" mov r1,%3;\n" // Machine type
" mov r2,%6;\n" // Kernel parameters
" mov pc,%0;\n" // Jump to kernel
"__xtramp_end__:\n"
: :
"r"(entry),
"r"(CYGARC_PHYSICAL_ADDRESS(base_addr)),
"r"(length),
"r"(CYGHWR_REDBOOT_ARM_MACHINE_TYPE),
"r"(CYGHWR_REDBOOT_ARM_LINUX_EXEC_ADDRESS),
"r"(CYGARC_PHYSICAL_ADDRESS(CYGHWR_REDBOOT_ARM_TRAMPOLINE_ADDRESS)),
"r"(CYGARC_PHYSICAL_ADDRESS(CYGHWR_REDBOOT_ARM_LINUX_TAGS_ADDRESS))
: "r0", "r1"
);
}
#endif // CYGHWR_REDBOOT_LINUX_EXEC_X_SWITCH
// copy the trampline code
memcpy((char *)CYGHWR_REDBOOT_ARM_TRAMPOLINE_ADDRESS,
__tramp_start__,
__tramp_end__ - __tramp_start__);
asm volatile (
CYGARC_HAL_MMU_OFF(%5)
"__tramp_start__:\n"
" cmp %1,%4;\n" // Default kernel load address. Relocate
" beq 2f;\n" // kernel image there if necessary, and
" cmp %2,#0;\n" // if size is non-zero
" beq 2f;\n"
"1:\n"
" ldr r0,[%1],#4;\n"
" str r0,[%4],#4;\n"
" subs %2,%2,#4;\n"
" bne 1b;\n"
"2:\n"
" mov r0,#0;\n" // Set board type
" mov r1,%3;\n" // Machine type
" mov r2,%6;\n" // Kernel parameters
" mov pc,%0;\n" // Jump to kernel
"__tramp_end__:\n"
: :
"r"(entry),
"r"(CYGARC_PHYSICAL_ADDRESS(base_addr)),
"r"(length),
"r"(CYGHWR_REDBOOT_ARM_MACHINE_TYPE),
"r"(target),
"r"(CYGARC_PHYSICAL_ADDRESS(CYGHWR_REDBOOT_ARM_TRAMPOLINE_ADDRESS)),
"r"(CYGARC_PHYSICAL_ADDRESS(CYGHWR_REDBOOT_ARM_LINUX_TAGS_ADDRESS))
: "r0", "r1"
);
}
#endif // HAL_PLATFORM_MACHINE_TYPE - otherwise we do not support this stuff...
// EOF redboot_linux_exec.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -