• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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