1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "bootloader.h" 18 #include "common.h" 19 #include "mtdutils/mtdutils.h" 20 #include "roots.h" 21 22 #include <errno.h> 23 #include <stdio.h> 24 #include <string.h> 25 26 static int get_bootloader_message_mtd(struct bootloader_message *out, const Volume* v); 27 static int set_bootloader_message_mtd(const struct bootloader_message *in, const Volume* v); 28 static int get_bootloader_message_block(struct bootloader_message *out, const Volume* v); 29 static int set_bootloader_message_block(const struct bootloader_message *in, const Volume* v); 30 31 int get_bootloader_message(struct bootloader_message *out) { 32 Volume* v = volume_for_path("/misc"); 33 if (strcmp(v->fs_type, "mtd") == 0) { 34 return get_bootloader_message_mtd(out, v); 35 } else if (strcmp(v->fs_type, "emmc") == 0) { 36 return get_bootloader_message_block(out, v); 37 } 38 LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type); 39 return -1; 40 } 41 42 int set_bootloader_message(const struct bootloader_message *in) { 43 Volume* v = volume_for_path("/misc"); 44 if (strcmp(v->fs_type, "mtd") == 0) { 45 return set_bootloader_message_mtd(in, v); 46 } else if (strcmp(v->fs_type, "emmc") == 0) { 47 return set_bootloader_message_block(in, v); 48 } 49 LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type); 50 return -1; 51 } 52 53 // ------------------------------ 54 // for misc partitions on MTD 55 // ------------------------------ 56 57 static const int MISC_PAGES = 3; // number of pages to save 58 static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page 59 60 static int get_bootloader_message_mtd(struct bootloader_message *out, 61 const Volume* v) { 62 size_t write_size; 63 mtd_scan_partitions(); 64 const MtdPartition *part = mtd_find_partition_by_name(v->device); 65 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) { 66 LOGE("Can't find %s\n", v->device); 67 return -1; 68 } 69 70 MtdReadContext *read = mtd_read_partition(part); 71 if (read == NULL) { 72 LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); 73 return -1; 74 } 75 76 const ssize_t size = write_size * MISC_PAGES; 77 char data[size]; 78 ssize_t r = mtd_read_data(read, data, size); 79 if (r != size) LOGE("Can't read %s\n(%s)\n", v->device, strerror(errno)); 80 mtd_read_close(read); 81 if (r != size) return -1; 82 83 memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out)); 84 return 0; 85 } 86 static int set_bootloader_message_mtd(const struct bootloader_message *in, 87 const Volume* v) { 88 size_t write_size; 89 mtd_scan_partitions(); 90 const MtdPartition *part = mtd_find_partition_by_name(v->device); 91 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) { 92 LOGE("Can't find %s\n", v->device); 93 return -1; 94 } 95 96 MtdReadContext *read = mtd_read_partition(part); 97 if (read == NULL) { 98 LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); 99 return -1; 100 } 101 102 ssize_t size = write_size * MISC_PAGES; 103 char data[size]; 104 ssize_t r = mtd_read_data(read, data, size); 105 if (r != size) LOGE("Can't read %s\n(%s)\n", v->device, strerror(errno)); 106 mtd_read_close(read); 107 if (r != size) return -1; 108 109 memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in)); 110 111 MtdWriteContext *write = mtd_write_partition(part); 112 if (write == NULL) { 113 LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); 114 return -1; 115 } 116 if (mtd_write_data(write, data, size) != size) { 117 LOGE("Can't write %s\n(%s)\n", v->device, strerror(errno)); 118 mtd_write_close(write); 119 return -1; 120 } 121 if (mtd_write_close(write)) { 122 LOGE("Can't finish %s\n(%s)\n", v->device, strerror(errno)); 123 return -1; 124 } 125 126 LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : ""); 127 return 0; 128 } 129 130 131 // ------------------------------------ 132 // for misc partitions on block devices 133 // ------------------------------------ 134 135 static int get_bootloader_message_block(struct bootloader_message *out, 136 const Volume* v) { 137 FILE* f = fopen(v->device, "rb"); 138 if (f == NULL) { 139 LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); 140 return -1; 141 } 142 struct bootloader_message temp; 143 int count = fread(&temp, sizeof(temp), 1, f); 144 if (count != 1) { 145 LOGE("Failed reading %s\n(%s)\n", v->device, strerror(errno)); 146 return -1; 147 } 148 if (fclose(f) != 0) { 149 LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno)); 150 return -1; 151 } 152 memcpy(out, &temp, sizeof(temp)); 153 return 0; 154 } 155 156 static int set_bootloader_message_block(const struct bootloader_message *in, 157 const Volume* v) { 158 FILE* f = fopen(v->device, "wb"); 159 if (f == NULL) { 160 LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); 161 return -1; 162 } 163 int count = fwrite(in, sizeof(*in), 1, f); 164 if (count != 1) { 165 LOGE("Failed writing %s\n(%s)\n", v->device, strerror(errno)); 166 return -1; 167 } 168 if (fclose(f) != 0) { 169 LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno)); 170 return -1; 171 } 172 return 0; 173 } 174