blob: 1cd621a4714708b5adf9567668fec9cad78056f5 [file] [log] [blame]
/*
* Copyright 2013 Google Inc.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <libpayload.h>
#include <usb/usb.h>
#include <vboot_nvstorage.h>
#include <vboot_api.h>
#include "base/init_funcs.h"
#include "base/timestamp.h"
#include "config.h"
#include "debug/cli/common.h"
#include "drivers/bus/usb/usb.h"
#include "drivers/input/input.h"
#include "drivers/net/net.h"
#include "drivers/power/power.h"
#include "net/uip.h"
#include "net/uip_arp.h"
#include "netboot/dhcp.h"
#include "netboot/netboot.h"
#include "netboot/params.h"
#include "netboot/tftp.h"
#include "vboot/boot.h"
#include "vboot/util/flag.h"
static void enable_graphics(void)
{
if (!CONFIG_OPROM_MATTERS)
return;
int oprom_loaded = flag_fetch(FLAG_OPROM);
// Manipulating vboot's internal data and calling its internal
// functions is NOT NICE and will give you athlete's foot and make
// you unpopular at parties. Right now it's the only way to ensure
// graphics are enabled, though, so it's a necessary evil.
if (!oprom_loaded) {
printf("Enabling graphics.\n");
VbNvContext context;
VbExNvStorageRead(context.raw);
VbNvSetup(&context);
VbNvSet(&context, VBNV_OPROM_NEEDED, 1);
VbNvTeardown(&context);
VbExNvStorageWrite(context.raw);
printf("Rebooting.\n");
if (cold_reboot())
halt();
}
}
static void print_ip_addr(const uip_ipaddr_t *ip)
{
printf("%d.%d.%d.%d", uip_ipaddr1(ip), uip_ipaddr2(ip),
uip_ipaddr3(ip), uip_ipaddr4(ip));
}
static void print_mac_addr(const uip_eth_addr *mac)
{
for (int i = 0; i < ARRAY_SIZE(mac->addr); i++)
printf("%s%02x", i ? ":" : "", mac->addr[i]);
}
static void * const payload = (void *)(uintptr_t)CONFIG_KERNEL_START;
static const uint32_t MaxPayloadSize = CONFIG_KERNEL_SIZE;
static char cmd_line[4096] = "lsm.module_locking=0 cros_netboot_ramfs "
"cros_factory_install cros_secure cros_netboot";
void netboot(uip_ipaddr_t *tftp_ip, char *bootfile, char *argsfile, char *args)
{
dc_usb_initialize();
printf("Looking for network device... ");
while (!net_get_device())
usb_poll();
printf("done.\n");
printf("Waiting for link... ");
int ready = 0;
while (!ready) {
if (net_ready(&ready))
halt();
}
mdelay(200); // some dongles need more time than they think
printf("done.\n");
// Start up the network stack.
uip_init();
// Plug in the MAC address.
const uip_eth_addr *mac_addr = net_get_mac();
if (!mac_addr)
halt();
printf("MAC: ");
print_mac_addr(mac_addr);
printf("\n");
uip_setethaddr(*mac_addr);
// Find out who we are.
uip_ipaddr_t my_ip, next_ip, server_ip;
const char *dhcp_bootfile;
while (dhcp_request(&next_ip, &server_ip, &dhcp_bootfile))
printf("Dhcp failed, retrying.\n");
printf("My ip is ");
uip_gethostaddr(&my_ip);
print_ip_addr(&my_ip);
printf("\nThe DHCP server ip is ");
print_ip_addr(&server_ip);
printf("\n");
if (!tftp_ip) {
tftp_ip = &next_ip;
printf("TFTP server IP supplied by DHCP server: ");
} else {
printf("TFTP server IP predefined by user: ");
}
print_ip_addr(tftp_ip);
printf("\n");
// Download the bootfile.
uint32_t size;
if (!bootfile) {
bootfile = (char *)dhcp_bootfile;
printf("Bootfile supplied by DHCP server: %s\n", bootfile);
} else {
printf("Bootfile predefined by user: %s\n", bootfile);
}
if (tftp_read(payload, tftp_ip, bootfile, &size, MaxPayloadSize)) {
printf("Tftp failed.\n");
if (dhcp_release(server_ip))
printf("Dhcp release failed.\n");
halt();
}
printf("The bootfile was %d bytes long.\n", size);
// Try to download command line file via TFTP if argsfile is specified
if (argsfile && !(tftp_read(cmd_line, tftp_ip, argsfile, &size,
sizeof(cmd_line) - 1))) {
while (cmd_line[size - 1] <= ' ') // strip trailing whitespace
if (!--size) break; // and control chars (\n, \r)
cmd_line[size] = '\0';
while (size--) // replace inline control
if (cmd_line[size] < ' ') // chars with spaces
cmd_line[size] = ' ';
printf("Command line loaded dynamically from TFTP file: %s\n",
argsfile);
// If that fails or file wasn't specified fall back to args parameter
} else if (args) {
if (args != cmd_line)
strncpy(cmd_line, args, sizeof(cmd_line) - 1);
printf("Command line predefined by user.\n");
}
// We're done on the network, so release our IP.
if (dhcp_release(server_ip)) {
printf("Dhcp release failed.\n");
halt();
}
// Add tftp server IP into command line.
static const char def_tftp_cmdline[] = " tftpserverip=xxx.xxx.xxx.xxx";
int cmd_line_size = strlen(cmd_line);
if (cmd_line_size + sizeof(def_tftp_cmdline) - 1 >= sizeof(cmd_line)) {
printf("Out of space adding TFTP server IP to the command line.\n");
return;
}
sprintf(&cmd_line[cmd_line_size], " tftpserverip=%d.%d.%d.%d",
uip_ipaddr1(tftp_ip), uip_ipaddr2(tftp_ip),
uip_ipaddr3(tftp_ip), uip_ipaddr4(tftp_ip));
printf("The command line is: %s\n", cmd_line);
// Boot.
boot(payload, cmd_line, NULL, NULL);
}
int main(void) __attribute__((weak, alias("netboot_entry")));
int netboot_entry(void)
{
// Initialize some consoles.
serial_console_init();
cbmem_console_init();
video_console_init();
input_init();
printf("\n\nStarting netboot on " CONFIG_BOARD "...\n");
timestamp_init();
if (run_init_funcs())
halt();
// Make sure graphics are available if they aren't already.
enable_graphics();
if (CONFIG_CLI)
console_loop();
srand(timer_raw_value());
uip_ipaddr_t *tftp_ip;
char *bootfile, *argsfile;
if (netboot_params_read(&tftp_ip, cmd_line, sizeof(cmd_line),
&bootfile, &argsfile))
printf("ERROR: Failed to read netboot parameters from flash\n");
netboot(tftp_ip, bootfile, argsfile, cmd_line);
// We should never get here.
printf("Got to the end!\n");
halt();
return 0;
}