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