// // Execute a Linux kernel - this is a RedBoot CLI command // static void do_exec(int argc, char *argv[]) { unsigned long entry; bool wait_time_set, cmd_line_set; int wait_time; char *cmd_line; char *cline; struct option_info opts[2]; hal_virtual_comm_table_t *__chan; int baud_rate; bd_t *board_info; CYG_INTERRUPT_STATE oldints; unsigned long sp = CYGMEM_REGION_ram+CYGMEM_REGION_ram_SIZE; init_opts(&opts[0], 'w', true, OPTION_ARG_TYPE_NUM, (void *)&wait_time, (bool *)&wait_time_set, "wait timeout"); init_opts(&opts[1], 'c', true, OPTION_ARG_TYPE_STR, (void *)&cmd_line, (bool *)&cmd_line_set, "kernel command line"); entry = entry_address; // Default from last 'load' operation if (!scan_opts(argc, argv, 1, opts, 2, (void *)&entry, OPTION_ARG_TYPE_NUM, "[physical] starting address")) { return; } if (entry == (unsigned long)NO_MEMORY) { diag_printf("Can't execute Linux - invalid entry address\n"); return; } // Determine baud rate on current console __chan = CYGACC_CALL_IF_CONSOLE_PROCS(); baud_rate = CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_GETBAUD); if (baud_rate <= 0) { baud_rate = CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD; } // Make a little space at the top of the stack, and align to // 64-bit boundary. sp = (sp-128) & ~7; // The Linux boot code uses this space for FIFOs // Copy the commandline onto the stack, and set the SP to just below it. if (cmd_line_set) { int len,i; // get length of string for( len = 0; cmd_line[len] != '\0'; len++ ); // decrement sp by length of string and align to // word boundary. sp = (sp-(len+1)) & ~3; // assign this SP value to command line start cline = (char *)sp; // copy command line over. for( i = 0; i < len; i++ ) cline[i] = cmd_line[i]; cline[len] = '\0'; } else { cline = (char *)NULL; } // Set up parameter struct at top of stack sp = sp-sizeof(bd_t); board_info = (bd_t *)sp; memset(board_info, sizeof(*board_info), 0); board_info->bi_tag = 0x42444944; board_info->bi_size = sizeof(*board_info); board_info->bi_revision = 1; board_info->bi_bdate = 0x06012002; board_info->bi_memstart = CYGMEM_REGION_ram; board_info->bi_memsize = CYGMEM_REGION_ram_SIZE; board_info->bi_baudrate = baud_rate; board_info->bi_cmdline = cline; #ifdef CYGPKG_REDBOOT_NETWORKING memcpy(board_info->bi_enetaddr, __local_enet_addr, sizeof(enet_addr_t)); #endif // Call platform specific code to fill in the platform/architecture specific details plf_redboot_linux_exec(board_info); // adjust SP to 64 byte boundary, and leave a little space // between it and the commandline for PowerPC calling // conventions. sp = (sp-64)&~63; 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 at %p - abort with ^C within %d seconds\n", (void *)entry, wait_time); while (script_timeout_ms >= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT) { int res; char line[80]; 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; } } #ifdef CYGPKG_IO_ETH_DRIVERS eth_drv_stop(); #endif // Disable interrupts HAL_DISABLE_INTERRUPTS(oldints); // Put the caches to sleep. HAL_DCACHE_SYNC(); HAL_ICACHE_DISABLE(); HAL_DCACHE_DISABLE(); HAL_DCACHE_SYNC(); HAL_ICACHE_INVALIDATE_ALL(); HAL_DCACHE_INVALIDATE_ALL(); // diag_printf("entry %08x, sp %08x, info %08x, cmd line %08x, baud %d\n", // entry, sp, board_info, cline, baud_rate); // breakpoint(); // Call into Linux __asm__ volatile ( // Start by disabling MMU - the mappings are // 1-1 so this should not cause any problems "mfmsr 3\n" "li 4,0xFFFFFFCF\n" "and 3,3,4\n" "sync\n" "mtmsr 3\n" "sync\n" // Now set up parameters to jump into linux "mtlr %0\n" // set entry address in LR "mr 1,%1\n" // set stack pointer "mr 3,%2\n" // set board info in R3 "mr 4,%3\n" // set command line in R4 "blr \n" // jump into linux : : "r"(entry),"r"(sp),"r"(board_info),"r"(cline) : "r3", "r4" ); }
int xyzModem_stream_open (connection_info_t * info, int *err) { #ifdef REDBOOT int console_chan; #endif int stat = 0; int retries = xyzModem_MAX_RETRIES; int crc_retries = xyzModem_MAX_RETRIES_WITH_CRC; /* ZM_DEBUG(zm_out = zm_out_start); */ #ifdef xyzModem_zmodem if (info->mode == xyzModem_zmodem) { *err = xyzModem_noZmodem; return -1; } #endif #ifdef REDBOOT /* Set up the I/O channel. Note: this allows for using a different port in the future */ console_chan = CYGACC_CALL_IF_SET_CONSOLE_COMM (CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT); if (info->chan >= 0) { CYGACC_CALL_IF_SET_CONSOLE_COMM (info->chan); } else { CYGACC_CALL_IF_SET_CONSOLE_COMM (console_chan); } xyz.__chan = CYGACC_CALL_IF_CONSOLE_PROCS (); CYGACC_CALL_IF_SET_CONSOLE_COMM (console_chan); CYGACC_COMM_IF_CONTROL (*xyz.__chan, __COMMCTL_SET_TIMEOUT, xyzModem_CHAR_TIMEOUT); #else /* TODO: CHECK ! */ int dummy = 0; xyz.__chan = &dummy; #endif xyz.len = 0; xyz.crc_mode = true; xyz.at_eof = false; xyz.tx_ack = false; xyz.mode = info->mode; xyz.total_retries = 0; xyz.total_SOH = 0; xyz.total_STX = 0; xyz.total_CAN = 0; #ifdef USE_YMODEM_LENGTH xyz.read_length = 0; xyz.file_length = 0; #endif CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK)); if (xyz.mode == xyzModem_xmodem) { /* X-modem doesn't have an information header - exit here */ xyz.next_blk = 1; return 0; } while (retries-- > 0) { stat = xyzModem_get_hdr (); if (stat == 0) { /* Y-modem file information header */ if (xyz.blk == 0) { #ifdef USE_YMODEM_LENGTH /* skip filename */ while (*xyz.bufp++); /* get the length */ parse_num ((char *) xyz.bufp, &xyz.file_length, NULL, " "); #endif /* The rest of the file name data block quietly discarded */ xyz.tx_ack = true; } xyz.next_blk = 1; xyz.len = 0; return 0; } else if (stat == xyzModem_timeout) { if (--crc_retries <= 0) xyz.crc_mode = false; CYGACC_CALL_IF_DELAY_US (5 * 100000); /* Extra delay for startup */ CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK)); xyz.total_retries++; ZM_DEBUG (zm_dprintf ("NAK (%d)\n", __LINE__)); } if (stat == xyzModem_cancel) { break; } } *err = stat; ZM_DEBUG (zm_flush ()); return -1; }