/* * Copyright (C) 2014 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 #include #include #include #include #include #include "BootHead.h" #include "Utils.h" #define SD_UBOOT_SECTOR_START_DEFAULT 32800 /* #define MMC_BLOCK_MAJOR 179 typedef struct mmc_ioc_erase_cmd { unsigned int flags; unsigned int start_sec; unsigned int size_sec; // For 64-bit machines, the next member, ``__u64 data_ptr``, wants to // be 8-byte aligned. Make sure this struct is the same size when // built for 32-bit. __u32 __pad; // DAT buffer __u64 data_ptr; }mmc_ioc_erase_cmd; #define MMC_IOC_ERASE_CMD _IOWR(MMC_BLOCK_MAJOR, 1, struct mmc_ioc_erase_cmd) #define UBOOT_MAGIC "uboot" #define BOOT1_MAGIC "eGON.BT1" #define BOOT0_MAGIC "eGON.BT0" */ #define CMDLINE_FILE_PATH "/proc/cmdline" #define VERIFIED_BOOT "androidboot.verifiedbootstate" static int _is_secure = 0; static int spliteKeyAndValue(char* str, char** key, char** value){ int elocation = strcspn(str,"="); if (elocation < 0){ return -1; } str[elocation] = '\0'; *key = str; *value = str + elocation + 1; return 0; } static int getInfoFromCmdline(const char* key, char* value) { FILE* fp; char cmdline[1024]; //read partition info from /proc/cmdline if ((fp = fopen(CMDLINE_FILE_PATH,"r")) == NULL) { bb_debug("can't open /proc/cmdline \n"); // goto error; return -1; } fgets(cmdline,1024,fp); fclose(fp); if (strstr(cmdline, VERIFIED_BOOT)) _is_secure = 1; else _is_secure = 0; // bb_debug("%s\n", cmdline); //splite the cmdline by space char* p = NULL; char* lkey = NULL; char* lvalue = NULL; p = strtok(cmdline, " "); if (!spliteKeyAndValue(p, &lkey, &lvalue)){ if (!strcmp(lkey,key)){ goto done; } } // bb_debug("the first k-v is %s\n", p); while ((p = strtok(NULL, " "))){ // bb_debug("the other k-v is %s\n", p); if (!spliteKeyAndValue(p, &lkey, &lvalue)){ if (!strcmp(lkey,key)){ goto done; } } } bb_debug("no key named %s in cmdline.\n", key); strcpy(value, "-1"); return -1; done: strcpy(value, lvalue); return 0; } int getFlashType() { char ctype[8]; getInfoFromCmdline("boot_type", ctype); bb_debug("flash type = %s\n", ctype); int flash_type = atoi(ctype); //atoi出错时会返回0,当ctype字符串为0时也会返回0,所以这里要判断是否出错. if (flash_type == 0 && ctype[0] != '0') { return FLASH_TYPE_UNKNOW; } return flash_type; } #define CHECK_SOC_SECURE_ATTR 0x00 #define CHECK_BOOT_SECURE_ATTR 0x04 /* * Check secure solution or not * Return 0 if normal , return 1 if secure */ int check_soc_is_secure(void) { return _is_secure; /*int fd, ret; fd = open("/dev/sunxi_soc_info", O_RDWR); if (fd == -1) { bb_debug("open /dev/sunxi_soc_info failed!\n"); return 0 ; } ret = ioctl(fd, CHECK_SOC_SECURE_ATTR, NULL); if (ret) {// ret=1 in secure case bb_debug("soc is secure. (return value:%x)\n", ret); } else { bb_debug("soc is normal. (return value:%x)\n", ret); ret = ioctl(fd, CHECK_BOOT_SECURE_ATTR, NULL); if (ret) bb_debug("secure boot for normal case\n"); } close(fd); return ret;*/ } int getBufferExtractCookieOfFile(const char* path, BufferExtractCookie* cookie) { if (cookie == NULL) { // printf("get file stat failed!\n"); return -1; } struct stat statbuff; if (stat(path, &statbuff) < 0) { bb_debug("get file stat failed!!\n"); return -1; } cookie->len = statbuff.st_size; // bb_debug("file size is %d\n",(int)cookie->len); unsigned char* buffer = reinterpret_cast(malloc(cookie->len)); if (buffer==NULL) return -1; FILE* fp = fopen(path,"r"); if (fp == NULL) { bb_debug("open file failed!\n"); free(buffer); return -1; } if (!fread(buffer, cookie->len, 1, fp)) { bb_debug("read file failed!\n"); free(buffer); fclose(fp); return -1; } cookie->buffer = buffer; fclose(fp); return 0; } static int verify_toc_addsum(void *mem_base, unsigned int size, unsigned int *psum) { unsigned int *buf; unsigned int count; unsigned int src_sum; unsigned int sum; /* 生成校验和 */ src_sum = *psum; // 从Boot_file_head中的“check_sum”字段取出校验和 bb_debug("read sum :0x%x\n",src_sum); *psum = STAMP_VALUE; // 将STAMP_VALUE写入Boot_file_head中的“check_sum”字段 count = size >> 2; // 以 字(4bytes)为单位计数 sum = 0; buf = (unsigned int *)mem_base; do { sum += *buf++; // 依次累加,求得校验和 sum += *buf++; // 依次累加,求得校验和 sum += *buf++; // 依次累加,求得校验和 sum += *buf++; // 依次累加,求得校验和 } while ((count -= 4) > (4 - 1)); while (count-- > 0) sum += *buf++; *psum = src_sum; // 恢复Boot_file_head中的“check_sum”字段的值 bb_debug("calc sum :0x%x\n",sum); if (sum == src_sum) return 0; // 校验成功 else return -1; // 校验失败 } int checkBoot0Sum(BufferExtractCookie* cookie) { standard_boot_file_head_t *head_p; unsigned int length; unsigned int *buf; unsigned int loop; unsigned int i; unsigned int sum; unsigned int csum; if (check_soc_is_secure()) { unsigned int *psum; psum = &(((toc0_private_head_t *)(cookie->buffer))->check_sum); return verify_toc_addsum(cookie->buffer, cookie->len, psum); } else { head_p = (standard_boot_file_head_t *)cookie->buffer; length = head_p->length; if ((length & 0x3) != 0) // must 4-byte-aligned return -1; if ((length > 32 * 1024) != 0 ) { bb_debug("boot0 file length over size!!\n"); } if ((length & (512 - 1)) != 0) { bb_debug("boot0 file did not aliged!!\n"); } buf = (unsigned int *)cookie->buffer; csum = head_p->check_sum; head_p->check_sum = STAMP_VALUE; // fill stamp loop = length >> 2; for (i = 0, sum = 0; i < loop; i++) sum += buf[i]; head_p->check_sum = csum; bb_debug("Boot0 -> File length is %u,original sum is %u,new sum is %u\n", length, head_p->check_sum, sum); return !(csum == sum); } } int checkUbootSum(BufferExtractCookie* cookie) { uboot_file_head *head_p; sbrom_toc1_head_info_t *head_toc1; unsigned int length; unsigned int *buf; unsigned int loop; unsigned int i; unsigned int sum; unsigned int csum; unsigned int *psum; if (check_soc_is_secure()) { psum = &(((sbrom_toc1_head_info_t *)(cookie->buffer))->add_sum); return verify_toc_addsum(cookie->buffer, cookie->len, psum); } else { head_toc1 = (sbrom_toc1_head_info_t *)(cookie->buffer); if (head_toc1->magic == TOC_MAIN_INFO_MAGIC) { psum = &(((sbrom_toc1_head_info_t *)(cookie->buffer))->add_sum); return verify_toc_addsum(cookie->buffer, cookie->len, psum); } else { head_p = (uboot_file_head *)cookie->buffer; length = head_p->length; if ((length & 0x3) != 0) // must 4-byte-aligned return -1; buf = (unsigned int *)cookie->buffer; csum = head_p->check_sum; head_p->check_sum = STAMP_VALUE; // fill stamp loop = length >> 2; for (i = 0, sum = 0; i < loop; i++) sum += buf[i]; head_p->check_sum = csum; bb_debug("Uboot -> File length is %u,original sum is %u,new sum is %u\n", length, head_p->check_sum, sum); return !(csum == sum); } } } int checkBoot1Sum(BufferExtractCookie* cookie) { boot1_file_head *head_p; unsigned int length; unsigned int *buf; unsigned int loop; unsigned int i; unsigned int sum; unsigned int csum; head_p = (boot1_file_head *)cookie->buffer; length = head_p->length; if ((length & 0x3) != 0) // must 4-byte-aligned return -1; buf = (unsigned int *)cookie->buffer; csum = head_p->check_sum; head_p->check_sum = STAMP_VALUE; // fill stamp loop = length >> 2; for (i = 0, sum = 0; i < loop; i++) sum += buf[i]; head_p->check_sum = csum; bb_debug("boot1:File length is %u,old sum is %u,new sum is %u\n", length, head_p->check_sum, sum); return !(csum == sum); } int getUbootstartsector(BufferExtractCookie* cookie) { if(check_soc_is_secure()){ return -1; } uboot_file_head_t *head_p = NULL; unsigned int start_sector = 0; head_p = (uboot_file_head_t *)cookie->buffer; if (head_p == NULL) return -1; start_sector = head_p->prvt_head.uboot_start_sector_in_mmc; if(start_sector == 0) { start_sector = SD_UBOOT_SECTOR_START_DEFAULT; } return (int)start_sector; } int genBoot0CheckSum(void *cookie) { standard_boot_file_head_t *head_p; unsigned int length; unsigned int *buf; unsigned int loop; unsigned int i; unsigned int sum; unsigned int *psum; if(check_soc_is_secure()){ toc0_private_head_t *head_t = (toc0_private_head_t *)cookie; psum = &(head_t->check_sum); length = head_t->length; }else{ head_p = (standard_boot_file_head_t *)cookie; psum = &head_p->check_sum ; length = head_p->length; } if( ( length & 0x3 ) != 0 ) // must 4-byte-aligned return -1; buf = (unsigned int *)cookie; *psum = STAMP_VALUE; // fill stamp loop = length >> 2; sum = 0 ; for( i = 0, sum = 0; i < loop; i++ ) sum += buf[i]; /* write back check sum */ *psum = sum; return 0 ; } int readWithSeek(int fd ,off_t offset, size_t bootsize, void *buffer){ memset(buffer, 0, bootsize); if (lseek(fd, 0, SEEK_SET) == -1) { bb_debug("reset the cursor failed! the error num is %d:%s\n", errno, strerror(errno)); return -1; } if (lseek(fd, offset, SEEK_CUR) == -1) { bb_debug("lseek failed! the error num is %d:%s\n", errno, strerror(errno)); return -1; } return read(fd,buffer,bootsize); long result = read(fd,buffer,bootsize); if (result==(long)bootsize) return 0; else { bb_debug("readWithSeek : fail need read %zu, but write %ld\n", bootsize, result); return -1; } } int writeWithSeek(int fd, void *buf, off_t offset, size_t bootsize){ if (lseek(fd, 0, SEEK_SET) == -1) { bb_debug("reset the cursor failed! the error num is %d:%s\n", errno, strerror(errno)); return -1; } if (lseek(fd, offset, SEEK_CUR) == -1) { bb_debug("lseek failed! the error num is %d:%s\n", errno, strerror(errno)); return -1; } bb_debug("Write : offset = 0x%lx, len= %zu\n", offset, bootsize); long result = write(fd, buf, bootsize); fsync(fd); if (result==(long)bootsize) return 0; else { bb_debug("Write fail: need write %zu, but write %ld\n", bootsize, result); return -1; } }