1c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project/* 2c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 3c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project * 4c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project * you may not use this file except in compliance with the License. 6c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project * You may obtain a copy of the License at 7c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project * 8c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project * 10c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project * See the License for the specific language governing permissions and 14c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project * limitations under the License. 15c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project */ 16c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project 17f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall#include <fs_mgr.h> 18c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project#include "bootloader.h" 19c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project#include "common.h" 20c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project#include "mtdutils/mtdutils.h" 21c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project#include "roots.h" 22c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project 23c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project#include <errno.h> 24c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project#include <stdio.h> 25c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project#include <string.h> 26cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker#include <sys/stat.h> 27cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker#include <unistd.h> 28c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project 29cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongkerstatic int get_bootloader_message_mtd(struct bootloader_message *out, const Volume* v); 30cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongkerstatic int set_bootloader_message_mtd(const struct bootloader_message *in, const Volume* v); 31cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongkerstatic int get_bootloader_message_block(struct bootloader_message *out, const Volume* v); 32cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongkerstatic int set_bootloader_message_block(const struct bootloader_message *in, const Volume* v); 3304611da55b13f9697173d3aa947b3a735b96c01fDoug Zongker 34cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongkerint get_bootloader_message(struct bootloader_message *out) { 35cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker Volume* v = volume_for_path("/misc"); 36b2ceb696d02ab0f9f297033820a51fdeac12c0afAdam Bliss if (v == NULL) { 37b2ceb696d02ab0f9f297033820a51fdeac12c0afAdam Bliss LOGE("Cannot load volume /misc!\n"); 38b2ceb696d02ab0f9f297033820a51fdeac12c0afAdam Bliss return -1; 39b2ceb696d02ab0f9f297033820a51fdeac12c0afAdam Bliss } 40cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker if (strcmp(v->fs_type, "mtd") == 0) { 41cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker return get_bootloader_message_mtd(out, v); 42cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker } else if (strcmp(v->fs_type, "emmc") == 0) { 43cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker return get_bootloader_message_block(out, v); 4404611da55b13f9697173d3aa947b3a735b96c01fDoug Zongker } 45cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type); 46cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker return -1; 4704611da55b13f9697173d3aa947b3a735b96c01fDoug Zongker} 4804611da55b13f9697173d3aa947b3a735b96c01fDoug Zongker 49cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongkerint set_bootloader_message(const struct bootloader_message *in) { 50cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker Volume* v = volume_for_path("/misc"); 51b2ceb696d02ab0f9f297033820a51fdeac12c0afAdam Bliss if (v == NULL) { 52b2ceb696d02ab0f9f297033820a51fdeac12c0afAdam Bliss LOGE("Cannot load volume /misc!\n"); 53b2ceb696d02ab0f9f297033820a51fdeac12c0afAdam Bliss return -1; 54b2ceb696d02ab0f9f297033820a51fdeac12c0afAdam Bliss } 55cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker if (strcmp(v->fs_type, "mtd") == 0) { 56cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker return set_bootloader_message_mtd(in, v); 57cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker } else if (strcmp(v->fs_type, "emmc") == 0) { 58cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker return set_bootloader_message_block(in, v); 5904611da55b13f9697173d3aa947b3a735b96c01fDoug Zongker } 60cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type); 61cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker return -1; 6204611da55b13f9697173d3aa947b3a735b96c01fDoug Zongker} 6304611da55b13f9697173d3aa947b3a735b96c01fDoug Zongker 64cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker// ------------------------------ 65cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker// for misc partitions on MTD 66cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker// ------------------------------ 6704611da55b13f9697173d3aa947b3a735b96c01fDoug Zongker 6804611da55b13f9697173d3aa947b3a735b96c01fDoug Zongkerstatic const int MISC_PAGES = 3; // number of pages to save 6904611da55b13f9697173d3aa947b3a735b96c01fDoug Zongkerstatic const int MISC_COMMAND_PAGE = 1; // bootloader command is this page 7004611da55b13f9697173d3aa947b3a735b96c01fDoug Zongker 71cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongkerstatic int get_bootloader_message_mtd(struct bootloader_message *out, 72cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker const Volume* v) { 73c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project size_t write_size; 74cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker mtd_scan_partitions(); 75f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall const MtdPartition *part = mtd_find_partition_by_name(v->blk_device); 76c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) { 77f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall LOGE("Can't find %s\n", v->blk_device); 78c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project return -1; 79c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project } 80c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project 81c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project MtdReadContext *read = mtd_read_partition(part); 82c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project if (read == NULL) { 83f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno)); 84c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project return -1; 85c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project } 86c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project 87c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project const ssize_t size = write_size * MISC_PAGES; 88c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project char data[size]; 89c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project ssize_t r = mtd_read_data(read, data, size); 90f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall if (r != size) LOGE("Can't read %s\n(%s)\n", v->blk_device, strerror(errno)); 91c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project mtd_read_close(read); 92c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project if (r != size) return -1; 93c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project 94c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out)); 95c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project return 0; 96c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project} 97cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongkerstatic int set_bootloader_message_mtd(const struct bootloader_message *in, 98cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker const Volume* v) { 99c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project size_t write_size; 100cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker mtd_scan_partitions(); 101f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall const MtdPartition *part = mtd_find_partition_by_name(v->blk_device); 102c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) { 103f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall LOGE("Can't find %s\n", v->blk_device); 104c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project return -1; 105c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project } 106c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project 107c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project MtdReadContext *read = mtd_read_partition(part); 108c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project if (read == NULL) { 109f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno)); 110c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project return -1; 111c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project } 112c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project 113c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project ssize_t size = write_size * MISC_PAGES; 114c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project char data[size]; 115c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project ssize_t r = mtd_read_data(read, data, size); 116f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall if (r != size) LOGE("Can't read %s\n(%s)\n", v->blk_device, strerror(errno)); 117c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project mtd_read_close(read); 118c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project if (r != size) return -1; 119c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project 120c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in)); 121c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project 122c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project MtdWriteContext *write = mtd_write_partition(part); 123c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project if (write == NULL) { 124f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno)); 125c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project return -1; 126c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project } 127c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project if (mtd_write_data(write, data, size) != size) { 128f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall LOGE("Can't write %s\n(%s)\n", v->blk_device, strerror(errno)); 129c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project mtd_write_close(write); 130c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project return -1; 131c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project } 132c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project if (mtd_write_close(write)) { 133f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall LOGE("Can't finish %s\n(%s)\n", v->blk_device, strerror(errno)); 134c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project return -1; 135c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project } 136c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project 137c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : ""); 138c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project return 0; 139c24a8e688a6312764254beac2b2520bb0c5e998dThe Android Open Source Project} 14004611da55b13f9697173d3aa947b3a735b96c01fDoug Zongker 141cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker 142cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker// ------------------------------------ 143cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker// for misc partitions on block devices 144cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker// ------------------------------------ 145cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker 146cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongkerstatic void wait_for_device(const char* fn) { 147cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker int tries = 0; 148cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker int ret; 149cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker struct stat buf; 150cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker do { 151cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker ++tries; 152cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker ret = stat(fn, &buf); 153cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker if (ret) { 154cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker printf("stat %s try %d: %s\n", fn, tries, strerror(errno)); 155cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker sleep(1); 156cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker } 157cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker } while (ret && tries < 10); 158cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker if (ret) { 159cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker printf("failed to stat %s\n", fn); 160cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker } 161cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker} 162cfd256a3328aac1199a35825b5daf04f5f4fc112Doug Zongker 163cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongkerstatic int get_bootloader_message_block(struct bootloader_message *out, 164cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker const Volume* v) { 165f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall wait_for_device(v->blk_device); 166f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall FILE* f = fopen(v->blk_device, "rb"); 167cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker if (f == NULL) { 168f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno)); 169cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker return -1; 170cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker } 171cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker struct bootloader_message temp; 172cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker int count = fread(&temp, sizeof(temp), 1, f); 173cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker if (count != 1) { 174f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall LOGE("Failed reading %s\n(%s)\n", v->blk_device, strerror(errno)); 175cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker return -1; 176cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker } 177cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker if (fclose(f) != 0) { 178f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno)); 179cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker return -1; 180cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker } 181cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker memcpy(out, &temp, sizeof(temp)); 182cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker return 0; 183cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker} 184cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker 185cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongkerstatic int set_bootloader_message_block(const struct bootloader_message *in, 186cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker const Volume* v) { 187f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall wait_for_device(v->blk_device); 188f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall FILE* f = fopen(v->blk_device, "wb"); 189cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker if (f == NULL) { 190f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno)); 191cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker return -1; 192cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker } 193cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker int count = fwrite(in, sizeof(*in), 1, f); 194cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker if (count != 1) { 195f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall LOGE("Failed writing %s\n(%s)\n", v->blk_device, strerror(errno)); 196cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker return -1; 197cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker } 198cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker if (fclose(f) != 0) { 199f35d1cef7c19db975a1295e8c23c7fb8bd2489f9Ken Sumrall LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno)); 200cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker return -1; 201cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker } 202cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker return 0; 203cc8cd3f3cac07f6927ead277ef390c000ae798d9Doug Zongker} 204