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
copy_block(FILE * f,unsigned char * data,size_t in_offset,size_t length,size_t out_offset)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
get_bootflag(FILE * f)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
set_bootflag(FILE * f,int value)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
update_bootloader(unsigned char * img_data,size_t img_size,char * block_fn,char * force_ro_fn)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
WriteBootloaderFn(const char * name,State * state,int argc,Expr * argv[])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
Register_librecovery_updater_manta()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