OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
| 3 * Use of this source code is governed by a BSD-style license that can be |
| 4 * found in the LICENSE file. |
| 5 * |
| 6 * Alternatively, this software may be distributed under the terms of the |
| 7 * GNU General Public License ("GPL") version 2 as published by the Free |
| 8 * Software Foundation. |
| 9 */ |
| 10 |
| 11 /* Debug commands for Chrome OS recovery mode firmware */ |
| 12 |
| 13 #include <common.h> |
| 14 #include <command.h> |
| 15 #include <lcd.h> |
| 16 #include <malloc.h> |
| 17 #include <mmc.h> |
| 18 #include <usb.h> |
| 19 |
| 20 #include <bmpblk_header.h> |
| 21 #include <chromeos/gbb_bmpblk.h> |
| 22 #include <chromeos/hardware_interface.h> |
| 23 |
| 24 #include <gbb_header.h> |
| 25 #include <load_firmware_fw.h> |
| 26 #include <load_kernel_fw.h> |
| 27 #include <chromeos/boot_device_impl.h> |
| 28 |
| 29 #define PREFIX "cros_rec: " |
| 30 |
| 31 #ifdef VBOOT_DEBUG |
| 32 #define WARN_ON_FAILURE(action) do { \ |
| 33 int return_code = (action); \ |
| 34 if (return_code != 0) \ |
| 35 debug(PREFIX "%s failed, returning %d\n", \ |
| 36 #action, return_code); \ |
| 37 } while (0) |
| 38 #else |
| 39 #define WARN_ON_FAILURE(action) action |
| 40 #endif |
| 41 |
| 42 /* MMC dev number of SD card */ |
| 43 #define MMC_DEV_NUM_SD 1 |
| 44 |
| 45 #define WAIT_MS_BETWEEN_PROBING 200 |
| 46 |
| 47 uint8_t *g_gbb_base = NULL; |
| 48 int g_is_dev = 0; |
| 49 |
| 50 static void sleep_ms(int msecond) |
| 51 { |
| 52 const ulong start = get_timer(0); |
| 53 const ulong delay = msecond * CONFIG_SYS_HZ / 1000; |
| 54 |
| 55 while (!ctrlc() && get_timer(start) < delay) |
| 56 udelay(100); |
| 57 } |
| 58 |
| 59 static int is_mmc_storage_present(void) |
| 60 { |
| 61 return mmc_legacy_init(MMC_DEV_NUM_SD) == 0; |
| 62 } |
| 63 |
| 64 static int is_usb_storage_present(void) |
| 65 { |
| 66 int i; |
| 67 /* TODO: Seek a better way to probe USB instead of restart it */ |
| 68 usb_stop(); |
| 69 i = usb_init(); |
| 70 #ifdef CONFIG_USB_STORAGE |
| 71 if (i >= 0) { |
| 72 /* Scanning bus for storage devices, mode = 1. */ |
| 73 return usb_stor_scan(1) == 0; |
| 74 } |
| 75 #else |
| 76 return i; |
| 77 #endif |
| 78 } |
| 79 |
| 80 static int write_log(void) |
| 81 { |
| 82 /* TODO: Implement it when Chrome OS firmware logging is ready. */ |
| 83 return 0; |
| 84 } |
| 85 |
| 86 static int clear_ram_not_in_use(void) |
| 87 { |
| 88 /* TODO: Implement it when the memory layout is defined. */ |
| 89 return 0; |
| 90 } |
| 91 |
| 92 static int load_and_boot_kernel(uint8_t *load_addr, size_t load_size) |
| 93 { |
| 94 LoadKernelParams par; |
| 95 block_dev_desc_t *dev_desc; |
| 96 VbNvContext vnc; |
| 97 int i, status; |
| 98 GoogleBinaryBlockHeader *gbbh = (GoogleBinaryBlockHeader *)g_gbb_base; |
| 99 char buffer[CONFIG_SYS_CBSIZE]; |
| 100 |
| 101 if ((dev_desc = get_bootdev()) == NULL) { |
| 102 printf(PREFIX "No boot device set yet\n"); |
| 103 return 1; |
| 104 } |
| 105 |
| 106 par.gbb_data = g_gbb_base; |
| 107 par.gbb_size = CONFIG_LENGTH_GBB; |
| 108 par.shared_data_blob = NULL; |
| 109 par.shared_data_size = 0; |
| 110 par.bytes_per_lba = (uint64_t) dev_desc->blksz; |
| 111 par.ending_lba = (uint64_t) get_limit() - 1; |
| 112 par.kernel_buffer = load_addr; |
| 113 par.kernel_buffer_size = load_size; |
| 114 par.boot_flags = BOOT_FLAG_RECOVERY | BOOT_FLAG_SKIP_ADDR_CHECK; |
| 115 /* TODO: load vnc.raw from NV storage */ |
| 116 par.nv_context = &vnc; |
| 117 |
| 118 if (g_is_dev) { |
| 119 par.boot_flags |= BOOT_FLAG_DEVELOPER; |
| 120 } |
| 121 |
| 122 status = LoadKernel(&par); |
| 123 |
| 124 if (vnc.raw_changed) { |
| 125 /* TODO: save vnc.raw to NV storage */ |
| 126 } |
| 127 |
| 128 switch (status) { |
| 129 case LOAD_KERNEL_SUCCESS: |
| 130 printf(PREFIX "Success; good kernel found on device\n"); |
| 131 printf(PREFIX "partition_number: %lld\n", |
| 132 par.partition_number); |
| 133 printf(PREFIX "bootloader_address: 0x%llx\n", |
| 134 par.bootloader_address); |
| 135 printf(PREFIX "bootloader_size: 0x%llx\n", par.bootloader_size); |
| 136 printf(PREFIX "partition_guid: "); |
| 137 for (i = 0; i < 16; i++) |
| 138 printf("%02x", par.partition_guid[i]); |
| 139 putc('\n'); |
| 140 |
| 141 lcd_clear(); |
| 142 |
| 143 strcpy(buffer, "console=ttyS0,115200n8 "); |
| 144 strcat(buffer, getenv("platform_extras")); |
| 145 setenv("bootargs", buffer); |
| 146 sprintf(buffer, "%lld", par.partition_number + 1); |
| 147 setenv("rootpart", buffer); |
| 148 |
| 149 source(CONFIG_LOADADDR + par.bootloader_address - |
| 150 0x100000, NULL); |
| 151 run_command("bootm ${loadaddr}", 0); |
| 152 break; |
| 153 case LOAD_KERNEL_NOT_FOUND: |
| 154 printf(PREFIX "No kernel found on device\n"); |
| 155 break; |
| 156 case LOAD_KERNEL_INVALID: |
| 157 printf(PREFIX "Only invalid kernels found on device\n"); |
| 158 break; |
| 159 case LOAD_KERNEL_RECOVERY: |
| 160 printf(PREFIX "Internal error; reboot to recovery mode\n"); |
| 161 break; |
| 162 case LOAD_KERNEL_REBOOT: |
| 163 printf(PREFIX "Internal error; reboot to current mode\n"); |
| 164 break; |
| 165 default: |
| 166 printf(PREFIX "Unexpected return status from LoadKernel: %d\n", |
| 167 status); |
| 168 return 1; |
| 169 } |
| 170 return 0; |
| 171 } |
| 172 |
| 173 static int load_recovery_image_in_mmc(void) |
| 174 { |
| 175 char buffer[CONFIG_SYS_CBSIZE]; |
| 176 sprintf(buffer, "mmcblk%dp", MMC_DEV_NUM_SD); |
| 177 setenv("devname", buffer); |
| 178 set_bootdev("mmc", MMC_DEV_NUM_SD, 0); |
| 179 return load_and_boot_kernel((uint8_t *)CONFIG_LOADADDR, 0x01000000); |
| 180 } |
| 181 |
| 182 static int load_recovery_image_in_usb(void) |
| 183 { |
| 184 /* TODO: Find the correct dev num of USB storage instead of always 0 */ |
| 185 setenv("devname", "sda"); |
| 186 set_bootdev("usb", 0, 0); |
| 187 return load_and_boot_kernel((uint8_t *)CONFIG_LOADADDR, 0x01000000); |
| 188 } |
| 189 |
| 190 static int init_gbb_in_ram(void) |
| 191 { |
| 192 firmware_storage_t file; |
| 193 if (init_firmware_storage(&file)) { |
| 194 debug(PREFIX "init_firmware_storage failed\n"); |
| 195 return -1; |
| 196 } |
| 197 g_gbb_base = malloc(CONFIG_LENGTH_GBB); |
| 198 if (!g_gbb_base) { |
| 199 debug(PREFIX "Unable to malloc g_gbb_base\n"); |
| 200 return -1; |
| 201 } |
| 202 if (read_firmware_device(&file, CONFIG_OFFSET_GBB, g_gbb_base, |
| 203 CONFIG_LENGTH_GBB)) { |
| 204 debug(PREFIX "Unable to read firmware to g_gbb_base\n"); |
| 205 return -1; |
| 206 } |
| 207 return 0; |
| 208 } |
| 209 |
| 210 static int show_screen(ScreenIndex scr) |
| 211 { |
| 212 static ScreenIndex cur_scr; |
| 213 if (cur_scr == scr) { |
| 214 return 0; |
| 215 } else { |
| 216 cur_scr = scr; |
| 217 return display_screen_in_bmpblk(g_gbb_base, scr); |
| 218 } |
| 219 } |
| 220 |
| 221 int do_cros_rec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
| 222 { |
| 223 WARN_ON_FAILURE(write_log()); |
| 224 WARN_ON_FAILURE(clear_ram_not_in_use()); |
| 225 WARN_ON_FAILURE(init_gbb_in_ram()); |
| 226 |
| 227 g_is_dev = is_developer_mode_gpio_asserted(); |
| 228 |
| 229 if (!g_is_dev) { |
| 230 /* Wait for user to plug out SD card and USB storage device */ |
| 231 while (is_mmc_storage_present() || is_usb_storage_present()) { |
| 232 show_screen(SCREEN_RECOVERY_MODE); |
| 233 sleep_ms(WAIT_MS_BETWEEN_PROBING); |
| 234 } |
| 235 } |
| 236 |
| 237 for (;;) { |
| 238 /* Wait for user to plug in SD card or USB storage device */ |
| 239 while (!is_mmc_storage_present() && !is_usb_storage_present()) { |
| 240 show_screen(SCREEN_RECOVERY_NO_OS); |
| 241 sleep_ms(WAIT_MS_BETWEEN_PROBING); |
| 242 } |
| 243 if (is_mmc_storage_present()) { |
| 244 WARN_ON_FAILURE(load_recovery_image_in_mmc()); |
| 245 /* Wait for user to plug out SD card */ |
| 246 while (is_mmc_storage_present()) { |
| 247 show_screen(SCREEN_RECOVERY_MISSING_OS); |
| 248 sleep_ms(WAIT_MS_BETWEEN_PROBING); |
| 249 } |
| 250 } else if (is_usb_storage_present()) { |
| 251 WARN_ON_FAILURE(load_recovery_image_in_usb()); |
| 252 /* Wait for user to plug out USB storage device */ |
| 253 while (is_usb_storage_present()) { |
| 254 show_screen(SCREEN_RECOVERY_MISSING_OS); |
| 255 sleep_ms(WAIT_MS_BETWEEN_PROBING); |
| 256 } |
| 257 } |
| 258 } |
| 259 |
| 260 /* This point is never reached */ |
| 261 return 0; |
| 262 } |
| 263 |
| 264 U_BOOT_CMD(cros_rec, 1, 1, do_cros_rec, "recovery mode firmware", NULL); |
OLD | NEW |