1 /* 2 * Copyright (C) 2012 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 <stdio.h> 18 #include <errno.h> 19 #include <stdarg.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <sys/types.h> 23 #include <sys/stat.h> 24 #include <fcntl.h> 25 #include <unistd.h> 26 27 #include "edify/expr.h" 28 29 // The bootloader block /dev/block/mmcblk0boot0 contains a low-level 30 // bootloader (BL1/BL2) followed by a "boot flag", followed by a 31 // primary copy of the full bootloader, then a backup copy of the full 32 // bootloader. The boot flag tells the low-level code which copy of 33 // the big bootloader to boot. 34 // 35 // The strategy here is to read the boot flag, write the *other* copy 36 // of the big bootloader, flip the boot flag to that freshly-written 37 // copy, write remaining copy of the big bootloader, then flip the 38 // flag back (so most of the time it will be booting the primary 39 // copy). At the end we update the BL1/BL2, which is slightly 40 // dangerous (there's no backup; if we fail during writing this part 41 // then the device is a brick). We could remove that before launch, 42 // or restrict it to only being written on test-keys/dev-keys devices. 43 44 #define BOOTFLAG_OFFSET (31*1024) 45 46 #define BL1BL2_LENGTH (31*1024) 47 48 #define INPUT_OFFSET (35*1024) 49 #define PRIMARY_OUTPUT_OFFSET (35*1024) 50 #define SECONDARY_OUTPUT_OFFSET (1280*1024) 51 #define BIG_LENGTH (1245*1024) 52 53 static void copy_block(FILE *f, unsigned char* data, size_t in_offset, 54 size_t length, size_t out_offset) { 55 if (fseek(f, out_offset, SEEK_SET) < 0) { 56 fprintf(stderr, "failed to seek to %d: %s\n", 57 out_offset, strerror(errno)); 58 return; 59 } 60 if (fwrite(data+in_offset, 1, length, f) != length) { 61 fprintf(stderr, "failed to write bootloader: %s\n", strerror(errno)); 62 return; 63 } 64 fflush(f); 65 fsync(fileno(f)); 66 } 67 68 static int get_bootflag(FILE *f) { 69 fseek(f, BOOTFLAG_OFFSET, SEEK_SET); 70 char buffer[8]; 71 if (fread(buffer, 1, 8, f) != 8) { 72 fprintf(stderr, "failed to read boot flag: %s\n", strerror(errno)); 73 return 0; 74 } 75 76 fprintf(stderr, "bootflag is [%c%c%c%c%c%c%c%c]\n", 77 buffer[0], buffer[1], buffer[2], buffer[3], 78 buffer[4], buffer[5], buffer[6], buffer[7]); 79 80 if (strncmp(buffer, "MANTABL", 7) != 0) return 0; 81 if (buffer[7] == '1') return 1; 82 if (buffer[7] == '2') return 2; 83 return 0; 84 } 85 86 static void set_bootflag(FILE* f, int value) { 87 unsigned char buffer[9] = "MANTABLx"; 88 buffer[7] = '0' + value; 89 copy_block(f, buffer, 0, 8, BOOTFLAG_OFFSET); 90 } 91 92 static int update_bootloader(unsigned char* img_data, 93 size_t img_size, 94 char* block_fn, 95 char* force_ro_fn) { 96 if (img_size != INPUT_OFFSET + BIG_LENGTH) { 97 fprintf(stderr, "expected bootloader.img of length %d; got %d\n", 98 INPUT_OFFSET + BIG_LENGTH, img_size); 99 return -1; 100 } 101 102 103 FILE* f = fopen(force_ro_fn, "w"); 104 if (!f) { 105 fprintf(stderr, "failed to open %s: %s\n", force_ro_fn, strerror(errno)); 106 return -1; 107 } 108 if (fwrite("0", 1, 1, f) != 1) { 109 fprintf(stderr, "failed to write %s: %s\n", force_ro_fn, strerror(errno)); 110 return -1; 111 } 112 fflush(f); 113 fsync(fileno(f)); 114 if (fclose(f) != 0) { 115 fprintf(stderr, "failed to close %s: %s\n", force_ro_fn, strerror(errno)); 116 return -1; 117 } 118 119 f = fopen(block_fn, "r+b"); 120 if (!f) { 121 fprintf(stderr, "failed to open %s: %s\n", block_fn, strerror(errno)); 122 return -1; 123 } 124 125 int i; 126 int bootflag = 0; 127 for (i = 0; i < 2; ++i) { 128 bootflag = get_bootflag(f); 129 130 switch (bootflag) { 131 case 1: 132 fprintf(stderr, "updating secondary copy of bootloader\n"); 133 copy_block(f, img_data, INPUT_OFFSET, BIG_LENGTH, SECONDARY_OUTPUT_OFFSET); 134 set_bootflag(f, 2); 135 break; 136 case 2: 137 fprintf(stderr, "updating primary copy of bootloader\n"); 138 copy_block(f, img_data, INPUT_OFFSET, BIG_LENGTH, PRIMARY_OUTPUT_OFFSET); 139 set_bootflag(f, 1); 140 break; 141 case 0: 142 fprintf(stderr, "no bootflag; updating entire bootloader block\n"); 143 copy_block(f, img_data, 0, img_size, 0); 144 i = 2; 145 break; 146 } 147 } 148 149 if (bootflag != 0) { 150 fprintf(stderr, "updating BL1/BL2\n"); 151 copy_block(f, img_data, 0, BL1BL2_LENGTH, 0); 152 } 153 154 fclose(f); 155 return 0; 156 } 157 158 Value* WriteBootloaderFn(const char* name, State* state, int argc, Expr* argv[]) 159 { 160 int result = -1; 161 Value* img; 162 Value* block_loc; 163 Value* force_ro_loc; 164 165 if (argc != 3) { 166 return ErrorAbort(state, "%s() expects 3 args, got %d", name, argc); 167 } 168 169 if (ReadValueArgs(state, argv, 3, &img, &block_loc, &force_ro_loc) < 0) { 170 return NULL; 171 } 172 173 if(img->type != VAL_BLOB || 174 block_loc->type != VAL_STRING || 175 force_ro_loc->type != VAL_STRING) { 176 FreeValue(img); 177 FreeValue(block_loc); 178 FreeValue(force_ro_loc); 179 return ErrorAbort(state, "%s(): argument types are incorrect", name); 180 } 181 182 result = update_bootloader(img->data, img->size, 183 block_loc->data, force_ro_loc->data); 184 FreeValue(img); 185 FreeValue(block_loc); 186 FreeValue(force_ro_loc); 187 return StringValue(strdup(result == 0 ? "t" : "")); 188 } 189 190 void Register_librecovery_updater_manta() { 191 fprintf(stderr, "installing samsung.manta updater extensions\n"); 192 193 RegisterFunction("samsung.manta.write_bootloader", WriteBootloaderFn); 194 } 195