Home | History | Annotate | Download | only in recovery
      1 /*
      2  * Copyright (C) 2011 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 <errno.h>
     18 #include <fcntl.h>
     19 #include <linux/fs.h>
     20 #include <stdio.h>
     21 #include <stdlib.h>
     22 #include <string.h>
     23 #include <sys/ioctl.h>
     24 #include <sys/types.h>
     25 #include <unistd.h>
     26 
     27 #include "bootloader.h"
     28 
     29 #define SECTOR_SIZE 512
     30 #define NUM_SECONDARY_GPT_SECTORS 34
     31 #define PIT_PARTITION_TABLE_SIZE 0x1000 // 4KB
     32 #define BOOT_PART_LEN 0x20000 // 128KB
     33 #define SBL_OFFSET (PIT_PARTITION_TABLE_SIZE + (BOOT_PART_LEN * 4))
     34 
     35 #define SMALL_BUFFER_SIZE 0x20
     36 
     37 // A combination of these defines the specification of the device.
     38 #define OMAP4460  0x1
     39 #define OMAP4430  0x2
     40 #define CHIP_HS   0x4
     41 #define CHIP_EMU  0x8
     42 #define MSV_PROD 0x10
     43 
     44 // Location of the PIT partition table in EMMC
     45 #define PIT_PARTITION_TABLE_LOCATION 0x4400
     46 
     47 static const char* FAMILY_LOCATION = "/sys/board_properties/soc/family";
     48 static const char* TYPE_LOCATION = "/sys/board_properties/soc/type";
     49 static const char* MSV_LOCATION = "/sys/board_properties/soc/msv";
     50 
     51 static const char* MMC_LOCATION = "/dev/block/mmcblk0";
     52 
     53 /* pit structure = header + (pit partition info * n) */
     54 struct pit_header {
     55         unsigned int magic;
     56         int count;              /* onenand + mmc partitions */
     57         int dummy[5];
     58 } __attribute__((packed));
     59 
     60 struct pit_partinfo {
     61         int binary;             /* BINARY_TYPE_ */
     62         int device;             /* PARTITION_DEV_TYPE_ */
     63         int id;                 /* partition id */
     64         int attribute;          /* PARTITION_ATTR_ */
     65         int update;             /* PARTITION_UPDATE_ATTR_ - dedicated. */
     66         unsigned int blksize;   /* mmc start sector */
     67         unsigned int blklen;    /* sector count */
     68         unsigned int offset;    /* file offset (in TAR) */
     69         unsigned int filesize;  /* file size */
     70         char name[32];          /* partition name */
     71         char filename[32];      /* file name */
     72         char deltaname[32];     /* delta file name - dedicated. */
     73 } __attribute__((packed));
     74 
     75 unsigned int read_whole_file(const char* fname, char* buffer,
     76                              int buffer_size) {
     77   memset(buffer, 0, buffer_size);
     78 
     79   FILE* f = fopen(fname, "rb");
     80   if (f == NULL) {
     81     fprintf(stderr, "Cannot open %s!\n", fname);
     82     return -1;
     83   }
     84 
     85   int read_byte_count = fread(buffer, 1, buffer_size - 1, f);
     86   fclose(f);
     87   if (read_byte_count < 0) {
     88     fprintf(stderr, "Couldn't read %s\n", fname);
     89     return -1;
     90   }
     91 
     92   // Remove any newlines at the end.
     93   while (buffer[read_byte_count - 1] == '\n') {
     94     buffer[--read_byte_count] = 0;
     95   }
     96 
     97   return 0;
     98 }
     99 
    100 // Get the specifications for this device
    101 int get_specification() {
    102   int spec = 0;
    103 
    104   char file_data[SMALL_BUFFER_SIZE];
    105 
    106   if (read_whole_file(FAMILY_LOCATION, file_data, SMALL_BUFFER_SIZE) == 0) {
    107     if (strcmp(file_data, "OMAP4430") == 0) {
    108       spec |= OMAP4430;
    109     } else if (strcmp(file_data, "OMAP4460") == 0) {
    110       spec |= OMAP4460;
    111     } else {
    112       fprintf(stderr, "Unknown family: %s\n", file_data);
    113       return -1;
    114     }
    115   } else {
    116     fprintf(stderr, "No family\n");
    117     return -1;
    118   }
    119 
    120   if (read_whole_file(TYPE_LOCATION, file_data, SMALL_BUFFER_SIZE) == 0) {
    121     if (strcmp(file_data, "HS") == 0) {
    122       spec |= CHIP_HS;
    123     } else if (strcmp(file_data, "EMU") == 0) {
    124       spec |= CHIP_EMU;
    125     } else {
    126       fprintf(stderr, "Unknown chip type: %s\n", file_data);
    127       return -1;
    128     }
    129   } else {
    130     fprintf(stderr, "No chip type\n");
    131     return -1;
    132   }
    133 
    134   // MSV is either prod (non-zero) or eng (zero). Default to eng.
    135   if (read_whole_file(MSV_LOCATION, file_data, SMALL_BUFFER_SIZE) == 0) {
    136     if (strtoul(file_data, NULL, 16) != 0) {
    137       spec |= MSV_PROD;
    138     }
    139   } else {
    140     fprintf(stderr, "No msv\n");
    141   }
    142 
    143   return spec;
    144 }
    145 
    146 
    147 // Four different xloaders are supported by bootloader.img:
    148 // 4460 EMU, 4460 HS (eng), 4460 HS (prod), 4430 HS.
    149 // The layout of the bootloader.img is:
    150 //
    151 // PIT Partition table (4KB)
    152 // 4460 EMU xloader (128KB)
    153 // 4460 HS (eng) xloader (128KB)
    154 // 4460 HS (prod) xloader (128KB)
    155 // 4430 HS xloader(128KB)
    156 // sbl (the rest)
    157 int get_xloader_offset() {
    158   int spec = get_specification();
    159 
    160   if (spec < 0) {
    161     return -1;
    162   }
    163 
    164   if (spec & OMAP4460 &&
    165       spec & CHIP_EMU) {
    166     return 0;
    167   } else if (spec & OMAP4460 &&
    168              spec & CHIP_HS &&
    169              !(spec & MSV_PROD)) {
    170     return BOOT_PART_LEN;
    171   } else if (spec & OMAP4460 &&
    172              spec & CHIP_HS &&
    173              spec & MSV_PROD) {
    174     return BOOT_PART_LEN * 2;
    175   } else if (spec & OMAP4430 &&
    176              spec & CHIP_HS) {
    177     return BOOT_PART_LEN * 3;
    178   }
    179 
    180   fprintf(stderr, "Unsupported spec for bootloader.img: %d", spec);
    181   return -1;
    182 }
    183 
    184 int write_pit_partition_table(const char* image_data,
    185                               size_t image_size) {
    186   int written = 0;
    187   int close_status = 0;
    188   int to_write;
    189   const char* curr;
    190 
    191 
    192   int mmcfd = open(MMC_LOCATION, O_RDWR);
    193   if (mmcfd < 0) {
    194     fprintf(stderr, "Could not open %s\n", MMC_LOCATION);
    195     return -1;
    196   }
    197 
    198   // zero out gpt magic field
    199   if (lseek(mmcfd, SECTOR_SIZE, SEEK_SET) < 0) {
    200     fprintf(stderr, "Couldn't seek to the start of sector 1\n");
    201     close(mmcfd);
    202     return -1;
    203   }
    204 
    205   char buf[SECTOR_SIZE];
    206   if (read(mmcfd, buf, SECTOR_SIZE) != SECTOR_SIZE) {
    207     fprintf(stderr, "Failed to read sector 1\n");
    208     close(mmcfd);
    209     return -1;
    210   }
    211 
    212   memset(buf, 0, 8);
    213 
    214   if (lseek(mmcfd, SECTOR_SIZE, SEEK_SET) < 0) {
    215     fprintf(stderr, "Couldn't seek to the start of sector 1, part 2\n");
    216     close(mmcfd);
    217     return -1;
    218   }
    219 
    220   to_write = SECTOR_SIZE;
    221   curr = buf;
    222   while (to_write > 0) {
    223     written = write(mmcfd, curr, to_write);
    224     if (written < 0 && errno != EINTR) {
    225       fprintf(stderr, "Couldn't overwrite sector 1\n");
    226       close(mmcfd);
    227       return -1;
    228     }
    229     if (written > 0) {
    230       to_write -= written;
    231       curr += written;
    232     }
    233   }
    234 
    235   // modify the pit partition info to reflect userdata size
    236   // before writing the pit partition table
    237   char pit_partition_copy[PIT_PARTITION_TABLE_SIZE];
    238   memcpy(pit_partition_copy, image_data, PIT_PARTITION_TABLE_SIZE);
    239 
    240   struct pit_header* hd = (struct pit_header*) pit_partition_copy;
    241   int i;
    242   for (i = 0; i < hd->count; i++) {
    243     struct pit_partinfo* pi = (struct pit_partinfo*)
    244         (pit_partition_copy + sizeof(*hd) + sizeof(*pi) * i);
    245     if (strcmp(pi->name, "userdata") == 0) {
    246       unsigned int num_sectors;
    247       if (ioctl(mmcfd, BLKGETSIZE, &num_sectors) < 0) {
    248         fprintf(stderr, "Couldn't get sector count\n");
    249         close(mmcfd);
    250         return -1;
    251       }
    252 
    253       // There are NUM_SECONDARY_GPT_SECTORS sectors reserved at the end of the
    254       // device to hold a backup copy of the GPT, so we subtract that number.
    255       pi->blklen = num_sectors - pi->blksize - NUM_SECONDARY_GPT_SECTORS;
    256       break;
    257     }
    258   }
    259 
    260   if (i == hd->count) {
    261     fprintf(stderr, "No userdata partition found\n");
    262     close(mmcfd);
    263     return -1;
    264   }
    265 
    266   // copy the modified pit partition table data to the correct location
    267   if (lseek(mmcfd, PIT_PARTITION_TABLE_LOCATION, SEEK_SET) < 0) {
    268     fprintf(stderr, "Couldn't seek to the pit partition table location\n");
    269     close(mmcfd);
    270     return -1;
    271   }
    272 
    273   to_write = PIT_PARTITION_TABLE_SIZE;
    274   curr = pit_partition_copy;
    275   while (to_write > 0) {
    276     written = write(mmcfd, curr, to_write);
    277     if (written < 0 && errno != EINTR) {
    278       fprintf(stderr, "Failed writing pit partition table\n");
    279       close(mmcfd);
    280       return -1;
    281     }
    282     if (written > 0) {
    283       to_write -= written;
    284       curr += written;
    285     }
    286   }
    287 
    288   if (close(mmcfd) != 0) {
    289     fprintf(stderr, "Failed to close file\n");
    290     return -1;
    291   }
    292 
    293   return 0;
    294 }
    295 
    296 int write_xloader(const char* image_data,
    297                   size_t image_size,
    298                   const char* xloader_loc) {
    299   int xloader_offset = get_xloader_offset();
    300 
    301   if (xloader_offset < 0) {
    302     return -1;
    303   }
    304 
    305   // The offsets into xloader part of the bootloader image
    306   xloader_offset += PIT_PARTITION_TABLE_SIZE;
    307 
    308   FILE* xloader = fopen(xloader_loc, "r+b");
    309   if (xloader == NULL) {
    310     fprintf(stderr, "Could not open %s\n", xloader_loc);
    311     return -1;
    312   }
    313 
    314   // index into the correct xloader offset
    315   int written = fwrite(image_data+xloader_offset, 1, BOOT_PART_LEN, xloader);
    316   int close_status = fclose(xloader);
    317   if (written != BOOT_PART_LEN || close_status != 0) {
    318     fprintf(stderr, "Failed writing to /xloader\n");
    319     return -1;
    320   }
    321 
    322   return 0;
    323 }
    324 
    325 int write_sbl(const char* image_data,
    326               size_t image_size,
    327               const char* sbl_loc) {
    328   unsigned int sbl_size = image_size - SBL_OFFSET;
    329   FILE* sbl = fopen(sbl_loc, "r+b");
    330   if (sbl == NULL) {
    331     fprintf(stderr, "Could not open %s\n", sbl_loc);
    332     return -1;
    333   }
    334 
    335   int written = fwrite(image_data+SBL_OFFSET, 1, sbl_size, sbl);
    336   int close_status = fclose(sbl);
    337   if (written != sbl_size || close_status != 0) {
    338     fprintf(stderr, "Failed writing to /sbl\n");
    339     return -1;
    340   }
    341 
    342   return 0;
    343 }
    344 
    345 int update_bootloader(const char* image_data,
    346                       size_t image_size,
    347                       const char* xloader_loc,
    348                       const char* sbl_loc) {
    349   if (image_size < SBL_OFFSET) {
    350     fprintf(stderr, "image size %d is too small\n", image_size);
    351     return -1;
    352   }
    353 
    354   if (write_pit_partition_table(image_data, image_size) < 0) {
    355     return -1;
    356   }
    357 
    358   if (write_xloader(image_data, image_size, xloader_loc) < 0) {
    359     return -1;
    360   }
    361 
    362   if (write_sbl(image_data, image_size, sbl_loc) < 0) {
    363     return -1;
    364   }
    365 
    366   return 0;
    367 }
    368