summaryrefslogtreecommitdiffstats
path: root/reflash-bootloader/reflash-bootloader.c
diff options
context:
space:
mode:
Diffstat (limited to 'reflash-bootloader/reflash-bootloader.c')
-rw-r--r--reflash-bootloader/reflash-bootloader.c359
1 files changed, 359 insertions, 0 deletions
diff --git a/reflash-bootloader/reflash-bootloader.c b/reflash-bootloader/reflash-bootloader.c
new file mode 100644
index 0000000..001d315
--- /dev/null
+++ b/reflash-bootloader/reflash-bootloader.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/reboot.h>
+#include <sys/stat.h>
+
+#define error(s, a...) \
+ { \
+ printf("error: " s "\n", ##a); \
+ exit(-1); \
+ }
+
+#define error_errno(s, a...) error(s ": %s", ##a, strerror(errno))
+
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+enum omap_type_enum {
+ OMAP4460_EMU = 0,
+ OMAP4460_HS,
+ OMAP4460_HS_PROD,
+ OMAP4430_HS,
+};
+
+struct omap_type {
+ const char *family;
+ const char *type;
+ unsigned long msv_val;
+ const char *msv_type;
+ off_t offset;
+} omap_type_list[] = {
+ [OMAP4460_EMU] = {"OMAP4460", "EMU", 0x00000000, "eng", 0x1000},
+ [OMAP4460_HS] = {"OMAP4460", "HS", 0x00000000, "eng", 0x21000},
+ [OMAP4460_HS_PROD] = {"OMAP4460", "HS", 0xf0000f00, "prod", 0x41000},
+ [OMAP4430_HS] = {"OMAP4430", "HS", 0x00000000, "eng", 0x61000},
+};
+
+#define IMG_PIT_OFFSET 0UL
+#define IMG_SBL_OFFSET 0x81000UL
+
+#define MMC_PIT_OFFSET 0x4400UL
+#define MMC_XLOADER_OFFSET 0x20000UL
+#define MMC_SBL_OFFSET 0x80000UL
+
+#define PIT_SIZE 0x1000UL
+#define XLOADER_SIZE 0x20000UL
+
+static void drop_caches(void)
+{
+ int fd;
+ int ret;
+ char buf[] = "3\n";
+
+ fd = open("/proc/sys/vm/drop_caches", O_WRONLY);
+ if (fd < 0)
+ error_errno("failed to open /proc/sys/vm/drop_caches");
+
+ ret = write(fd, buf, sizeof(buf));
+ if (ret < 0)
+ error_errno("failed to write to /proc/sys/vm/drop_caches");
+}
+
+static void read_file(const char *filename, char *buf, size_t size)
+{
+ int fd;
+ ssize_t ret;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ error_errno("failed to open %s", filename);
+
+ ret = read(fd, buf, size - 1);
+ if (ret < 0)
+ error_errno("failed to read %s", filename);
+ buf[ret] = 0;
+ while (buf[ret - 1] == '\n')
+ buf[--ret] = 0;
+
+ close(fd);
+}
+
+static const struct omap_type *get_omap_type(void)
+{
+ int fd;
+ char family[10];
+ char type[5];
+ char msv[9];
+ unsigned long msv_val;
+ ssize_t ret;
+ unsigned int i;
+
+ read_file("/sys/board_properties/soc/type", type, sizeof(type));
+ read_file("/sys/board_properties/soc/family", family, sizeof(family));
+ read_file("/sys/board_properties/soc/msv", msv, sizeof(msv));
+
+ msv_val = strtoul(msv, NULL, 16);
+
+ for (i = 0; i < ARRAY_SIZE(omap_type_list); i++)
+ if ((strcmp(omap_type_list[i].family, family) == 0) &&
+ (strcmp(omap_type_list[i].type, type) == 0) &&
+ msv_val == omap_type_list[i].msv_val)
+ return &omap_type_list[i];
+
+ error("unknown omap type %s %s %s (0x%08lx)", family, type, msv, msv_val);
+}
+
+static void zero_data(int to_fd, off_t to_offset, ssize_t size)
+{
+ char buf[4096];
+ int ret;
+ unsigned int to_write;
+
+ memset(buf, 0, sizeof(buf));
+
+ ret = lseek(to_fd, to_offset, SEEK_SET);
+ if (ret < 0)
+ error_errno("failed to seek output file to %lx", to_offset);
+
+ while (size != 0) {
+ to_write = size;
+ if (to_write > sizeof(buf))
+ to_write = sizeof(buf);
+
+ ret = write(to_fd, buf, to_write);
+ if (ret < 0)
+ error_errno("failed to write to output file");
+ size -= ret;
+ }
+}
+
+static void verify_data(int to_fd, off_t to_offset,
+ int from_fd, off_t from_offset,
+ ssize_t size)
+{
+ char buf_to[4096];
+ char buf_from[4096];
+ int ret;
+ int to_read;
+ int c;
+ char *ptr;
+
+ ret = lseek(to_fd, to_offset, SEEK_SET);
+ if (ret < 0)
+ error_errno("failed to seek output file to %lx", to_offset);
+
+ ret = lseek(from_fd, from_offset, SEEK_SET);
+ if (ret < 0)
+ error_errno("failed to seek input file to %lx", from_offset);
+
+ while (size != 0) {
+ to_read = sizeof(buf_to);
+ if (size > 0 && to_read > size)
+ to_read = size;
+
+ ptr = buf_to;
+ c = to_read;
+ while (c > 0) {
+ ret = read(to_fd, ptr, c);
+ if (ret < 0)
+ error_errno("failed to read from output file");
+ if (ret == 0 && size < 0)
+ return;
+ if (ret == 0)
+ error_errno("eof while reading output file");
+ ptr += ret;
+ c -= ret;
+ }
+
+ ptr = buf_from;
+ c = to_read;
+ while (c > 0) {
+ ret = read(from_fd, ptr, c);
+ if (ret < 0)
+ error_errno("failed to read from input file");
+ if (ret == 0 && size < 0)
+ return;
+ if (ret == 0)
+ error_errno("eof while reading input file");
+ ptr += ret;
+ c -= ret;
+ }
+
+ if (memcmp(buf_from, buf_to, to_read) != 0)
+ error("mismatch while verifying written data");
+
+ size -= to_read;
+ }
+}
+
+static void copy_data(int to_fd, off_t to_offset,
+ int from_fd, off_t from_offset,
+ ssize_t size)
+{
+ char buf[4096];
+ int ret;
+ int to_write;
+ const char *ptr;
+
+ ret = lseek(to_fd, to_offset, SEEK_SET);
+ if (ret < 0)
+ error_errno("failed to seek output file to %lx", to_offset);
+
+ ret = lseek(from_fd, from_offset, SEEK_SET);
+ if (ret < 0)
+ error_errno("failed to seek input file to %lx", from_offset);
+
+ while (size != 0) {
+ ret = read(from_fd, buf, sizeof(buf));
+ if (ret < 0)
+ error_errno("failed to read from input file");
+ if (ret == 0 && size > 0)
+ error_errno("eof while reading input file");
+ if (ret == 0)
+ return;
+
+ to_write = ret;
+ ptr = buf;
+
+ if (size > 0)
+ size -= to_write;
+
+ while (to_write > 0) {
+ ret = write(to_fd, ptr, to_write);
+ if (ret < 0)
+ error_errno("failed to write to output file");
+ to_write -= ret;
+ ptr += ret;
+ }
+ }
+}
+
+static void init(void)
+{
+ int ret;
+
+ umask(0);
+
+ ret = mkdir("/dev", 0755);
+ if (ret && errno != EEXIST)
+ error_errno("failed to create /dev");
+
+ ret = mkdir("/proc", 0755);
+ if (ret && errno != EEXIST)
+ error_errno("failed to create /proc");
+
+ ret = mkdir("/sys", 0755);
+ if (ret && errno != EEXIST)
+ error_errno("failed to create /sys");
+
+ ret = mount("proc", "/proc", "proc", 0, NULL);
+ if (ret)
+ error_errno("failed to mount proc");
+
+ ret = mount("sysfs", "/sys", "sysfs", 0, NULL);
+ if (ret)
+ error_errno("failed to mount sys");
+
+ ret = mkdir("/dev/block", 0755);
+ if (ret && errno != EEXIST)
+ error_errno("failed to create /dev/block");
+
+ ret = mknod("/dev/block/mmcblk0", S_IFBLK | 0755, makedev(179, 0));
+ if (ret)
+ error_errno("failed to create mmcblk0");
+}
+
+int main(int argc, char **argv)
+{
+ int in_fd;
+ int out_fd;
+ const struct omap_type *type;
+
+ if (getpid() == 1)
+ init();
+
+ in_fd = open("bootloader.img", O_RDONLY);
+ if (in_fd < 0)
+ error_errno("failed to open bootloader.img");
+
+ out_fd = open("/dev/block/mmcblk0", O_RDWR);
+ if (out_fd < 0)
+ error_errno("failed to open mmcblk0");
+
+ type = get_omap_type();
+
+ printf("Found %s %s %s\n", type->family, type->type, type->msv_type);
+
+ printf("Zeroing to end of sbl\n");
+ zero_data(out_fd, 0, MMC_SBL_OFFSET);
+
+ /* Don't write the partition table, let the bootloader do it on next boot */
+#if 0
+ printf("Writing partition-table from %lx to %lx\n",
+ IMG_PIT_OFFSET, MMC_PIT_OFFSET);
+ copy_data(out_fd, MMC_PIT_OFFSET, in_fd, IMG_PIT_OFFSET, PIT_SIZE);
+#endif
+
+ printf("Writing xloader from %lx to %lx\n",
+ type->offset, MMC_XLOADER_OFFSET);
+ copy_data(out_fd, MMC_XLOADER_OFFSET, in_fd, type->offset, XLOADER_SIZE);
+
+ printf("Writing sbl from %lx to %lx\n",
+ IMG_SBL_OFFSET, MMC_SBL_OFFSET);
+ copy_data(out_fd, MMC_SBL_OFFSET, in_fd, IMG_SBL_OFFSET, -1);
+
+#if 0
+ printf("Verifying partition table\n");
+ verify_data(out_fd, MMC_PIT_OFFSET, in_fd, IMG_PIT_OFFSET, PIT_SIZE);
+#endif
+
+ printf("Verifying xloader\n");
+ verify_data(out_fd, MMC_XLOADER_OFFSET, in_fd, type->offset, XLOADER_SIZE);
+
+ printf("Verifying sbl\n");
+ verify_data(out_fd, MMC_SBL_OFFSET, in_fd, IMG_SBL_OFFSET, -1);
+
+ printf("Syncing\n");
+ sync();
+
+ printf("Dropping caches\n");
+ drop_caches();
+
+ printf("Verifying xloader.img\n");
+ verify_data(out_fd, MMC_XLOADER_OFFSET, in_fd, type->offset, XLOADER_SIZE);
+
+ printf("Verifying sbl.img\n");
+ verify_data(out_fd, MMC_SBL_OFFSET, in_fd, IMG_SBL_OFFSET, -1);
+
+ printf("Done\n");
+
+ if (getpid() == 1) {
+ __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+ LINUX_REBOOT_CMD_RESTART2, "bootloader");
+
+ while (1) { sleep(1); }
+ }
+
+ return 0;
+}