Ejemplo n.º 1
0
//
// 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"
	             
	             );
}
Ejemplo n.º 2
0
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;
}