⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 redboot_linux_exec.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 2 页
字号:
        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 + -