summaryrefslogtreecommitdiff
path: root/drivers/mtd/wmt_env.c
diff options
context:
space:
mode:
authorSrikant Patnaik2015-01-11 12:28:04 +0530
committerSrikant Patnaik2015-01-11 12:28:04 +0530
commit871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch)
tree8718f573808810c2a1e8cb8fb6ac469093ca2784 /drivers/mtd/wmt_env.c
parent9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff)
downloadFOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized. Changes are basically to make it look like kernel structure.
Diffstat (limited to 'drivers/mtd/wmt_env.c')
-rwxr-xr-xdrivers/mtd/wmt_env.c1099
1 files changed, 1099 insertions, 0 deletions
diff --git a/drivers/mtd/wmt_env.c b/drivers/mtd/wmt_env.c
new file mode 100755
index 00000000..814dc60c
--- /dev/null
+++ b/drivers/mtd/wmt_env.c
@@ -0,0 +1,1099 @@
+/*
+ * This file is derived from crc32.c in U-Boot 1.1.4.
+ * For conditions of distribution and use, see copyright in crc32.c
+ */
+/*
+ * Some descriptions of such software. Copyright (c) 2008 WonderMedia Technologies, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software Foundation,
+ * either version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * WonderMedia Technologies, Inc.
+ * 10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/super.h>
+#include <mach/hardware.h>
+#include <linux/delay.h>
+#include <linux/semaphore.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include "mtdcore.h"
+#include "devices/wmt_sf.h"
+#include <linux/sha256.h>
+
+static DEFINE_SEMAPHORE(s_wmt_env_lock);
+
+#undef pr_err
+#undef pr_warning
+#undef pr_info
+#define pr_err(fmt, args...) printk("[WMTENV] %s, %d: " fmt, __func__, __LINE__, ##args)
+#define pr_warning(fmt, args...) printk("[WMTENV] %s, %d: " fmt, __func__, __LINE__, ##args)
+#define pr_info(fmt, args...) printk("[WMTENV] %s, %d: " fmt, __func__, __LINE__, ##args)
+
+
+extern unsigned int MTDSF_PHY_ADDR;
+extern int wmt_sfc_init(struct sfreg_t *sfc);
+extern int spi_flash_sector_erase(unsigned long addr, struct sfreg_t *sfreg);
+extern int spi_flash_sector_write(struct sfreg_t *sfreg,
+ unsigned char *sf_base_addr,
+ loff_t to, size_t len, u_char *buf);
+extern int sf_copy_env(char *dest, char *src, int len);
+extern int rsa_check(unsigned int pub_key_addr, unsigned int pub_key_size,
+ unsigned int sig_addr, unsigned int sig_size,
+ u8 *out_buf);
+
+extern int wmt_is_secure_enabled(void);
+
+/**
+ * white list when secure mode is enabled.
+ */
+static const char *env_white_list[] = {
+ "boot-method",
+ "ril.imei",
+ "wmt.modem.wakeuplight",
+ "wmt.display.tvformat",
+ "wmt.display.fb1",
+ "wmt.display.fb2",
+ "ethaddr",
+ NULL
+};
+
+static const unsigned int sf_crc_table[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d
+};
+#define DO1(buf) crc = sf_crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf) do {DO1(buf); DO1(buf); } while (0)
+#define DO4(buf) do {DO2(buf); DO2(buf); } while (0)
+#define DO8(buf) do {DO4(buf); DO4(buf); } while (0)
+
+static unsigned long uboot_crc32(u32 crc, unsigned char const *buf, size_t len)
+{
+ crc = crc ^ 0xffffffff;
+ while (len >= 8) {
+ DO8(buf);
+ len -= 8;
+ }
+
+ if (len) {
+ do {
+ DO1(buf);
+ } while (--len);
+ }
+ return crc ^ 0xffffffff;
+}
+
+#define SPI_FLASH_BASE 0xfff80000
+#define ENV_MAX_SIZE SZ_64K
+#define ENV_DATA_SIZE (ENV_MAX_SIZE - sizeof(unsigned int))
+#define ENV1 0
+#define ENV2 1
+#define MAX_NAME_SIZE 256
+#define MAX_VALUE_SIZE (4*1024)
+
+struct env_t {
+ unsigned long crc; /* CRC32 over data bytes */
+ unsigned char data[ENV_DATA_SIZE];
+};
+
+struct uboot_env {
+ struct env_t *env[2];
+ bool env_readed;
+ bool env_init;
+
+ // raw
+ void *io_base;
+ uint32_t offset[2];
+ size_t size[2];
+};
+
+static struct uboot_env *uboot_env;
+
+//GPIO_BASE_ADDR+0x100 should be bootstrap gpio, however, this is not true on some device.
+//As all wm8880 device boot from spi, i comment this out
+//static inline int boot_type(void)
+//{
+// uint32_t val = *((volatile unsigned int *)(GPIO_BASE_ADDR + 0x100));
+//
+// val = (val >> 1) & 0x3;
+// switch (val) {
+// case 0:
+// return SPI_FLASH_TYPE;
+// case 1:
+// return NAND_FLASH_TYPE;
+// case 2:
+// return NOR_FLASH_TYPE;
+// }
+// return -EINVAL;
+//}
+
+static inline unsigned char env_get_char(int type, int index)
+{
+ return uboot_env->env[type]->data[index];
+}
+
+/*
+ * Match a name / name=value pair
+ *
+ * s1 is either a simple 'name', or a 'name=value' pair.
+ * i2 is the environment index for a 'name2=value2' pair.
+ * If the names match, return the index for the value2, else NULL.
+ */
+static int envmatch(int type, unsigned char *s1, int i2)
+{
+ while (*s1 == env_get_char(type, i2++))
+ if (*s1++ == '=')
+ return i2;
+ if (*s1 == '\0' && env_get_char(type, i2-1) == '=')
+ return i2;
+ return -1;
+}
+
+
+/*
+ * raw interface
+ */
+static int raw_uboot_env_erase(int type)
+{
+ uint32_t offset;
+ int rc;
+
+ offset = uboot_env->offset[type]+0xfff80000-MTDSF_PHY_ADDR;
+
+ rc = spi_flash_sector_erase(offset, (struct sfreg_t *)SF_BASE_ADDR);
+ if (rc != ERR_OK) {
+ pr_err("spi_flash_sector_erase failed, try again\n");
+ rc = spi_flash_sector_erase(offset, (struct sfreg_t *)SF_BASE_ADDR);
+ if(rc != ERR_OK){
+ pr_err("spi_flash_sector_erase failed again\n");
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+static int raw_uboot_env_write(int type,struct env_t *env)
+{
+ uint32_t offset;
+ void *io_base = uboot_env->io_base;
+ int rc;
+
+ offset = uboot_env->offset[type];
+
+ rc = spi_flash_sector_write(((struct sfreg_t *)SF_BASE_ADDR),
+ io_base,
+ offset,
+ ENV_MAX_SIZE,
+ (u_char *)env);
+ if (rc != ENV_MAX_SIZE)
+ pr_err("spi_flash_sector_write failed: 0x%x\n", rc);
+
+ return 0;
+}
+
+
+static int raw_uboot_env_read(void)
+{
+ unsigned long crc32;
+ int i;
+
+ //REG32_VAL(PMCEU_ADDR) |= SF_CLOCK_EN;
+ //wmt_sfc_init((struct sfreg_t *)SF_BASE_ADDR);
+
+ // ubootenv
+ for (i = 0; i < 2; ++i) {
+ struct env_t *env = uboot_env->env[i];
+ uint32_t offset = uboot_env->offset[i];
+
+ _memcpy_fromio((void *)env, uboot_env->io_base + offset, ENV_MAX_SIZE);
+ crc32 = uboot_crc32(0, env->data, ENV_DATA_SIZE);
+ if (env->crc != crc32) {
+ pr_err("ERROR:crc32 0x%lx, env->crc 0x%lx ????\n\n", crc32, env->crc);
+ if (i == 0) // uboot env must pass crc32
+ {
+ return -EINVAL;
+ }
+ }
+ }
+ //REG32_VAL(PMCEU_ADDR) &= ~(SF_CLOCK_EN);
+ return 0;
+}
+
+static int save_env(int index, struct env_t *env)
+{
+ int ret;
+
+ if(env == NULL || index > 2|| index < 0)
+ return -1;
+
+ env->crc = uboot_crc32(0, env->data, ENV_DATA_SIZE);
+
+ ret = raw_uboot_env_erase(index);
+ if (ret)
+ return ret;
+
+ raw_uboot_env_write(index,env);
+
+ return 0;
+
+}
+
+
+static int env_init_if_needed(void)
+{
+ int i;
+
+ //if (boot_type() != SPI_FLASH_TYPE){
+ // pr_err("unsupported boot type!");
+ // return -EINVAL;
+ //}
+
+ if (!uboot_env) {
+ uboot_env = kzalloc(sizeof(*uboot_env), GFP_KERNEL);
+ if (!uboot_env){
+ pr_err("out of memory!\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < 2; ++i) {
+ uboot_env->env[i] = kmalloc(ENV_MAX_SIZE, GFP_KERNEL);
+ if (!uboot_env->env[i]){
+ pr_err("out of memory!\n");
+ return -ENOMEM;
+ }
+ }
+ }
+
+ if (!uboot_env->io_base) {
+ uboot_env->io_base = (void *)ioremap(0xFFF80000, SZ_512K);
+ if (!uboot_env->io_base) {
+ printk(KERN_WARNING "uboot_env ioremap fail\n");
+ return -EIO;
+ }
+ uboot_env->offset[0] = 0x50000; // 0xfffd0000
+ uboot_env->size[0] = 0x10000;
+ uboot_env->offset[1] = 0x60000; // 0xfffe0000
+ uboot_env->size[1] = 0x10000;
+ }
+
+ if(!uboot_env->env_init){
+ wmt_sfc_init((struct sfreg_t *)SF_BASE_ADDR);
+ uboot_env->env_init = true;
+ }
+ // read the uboot env only once
+ if (uboot_env->env_readed == false) {
+ if (raw_uboot_env_read()){
+ pr_err("read env fail!\n");
+ return -EINVAL;
+ }
+ uboot_env->env_readed = true;
+ }
+ return 0;
+}
+
+/*
+ * return 0 have env
+ * return others no such env
+ */
+int search_env(int index, char *varname)
+{
+ int i, j, k, nxt = 0;
+ int rcode = 0;
+
+ if (env_init_if_needed()){
+ rcode = -EIO;
+ goto out;
+ }
+
+ k = -1;
+ i = 0;
+ for (j = 0; env_get_char(index, j) != '\0'; j = nxt+1) {
+
+ for (nxt = j; env_get_char(index, nxt) != '\0'; ++nxt)
+ ;
+ k = envmatch(index, (unsigned char *)varname, j);
+ if (k < 0)
+ continue;
+ break;
+ }
+
+ if (k < 0) {
+ rcode++;
+ }
+
+out:
+ return rcode;
+}
+
+/*
+ * insert env to env buf
+ */
+int insert_env(int index, char *varname, char *varval)
+{
+ int len, oldval;
+ int rcode = 0;
+ unsigned char *env, *nxt = NULL;
+ unsigned char *env_data;
+
+ if(*varname == '\0'|| index > 2 || index < 0)
+ return -EINVAL;
+
+ env_data = uboot_env->env[index]->data;
+
+ /*
+ * search if variable with this name already exists
+ */
+ oldval = -1;
+ for (env = env_data; *env; env = nxt+1) {
+ for (nxt = env; *nxt; ++nxt)
+ ;
+ oldval = envmatch(index, (unsigned char *)varname, env - env_data);
+ if (oldval >= 0)
+ break;
+ }
+
+ /*
+ * Delete any existing definition
+ */
+ if (oldval >= 0) {
+ /* otp env can not overwrite */
+ //if (is_otp_env) {
+ // rcode = -EEXIST;
+ // goto out;
+ //}
+
+ if (*++nxt == '\0') {
+ if (env > env_data)
+ env--;
+ else
+ *env = '\0';
+ } else {
+ for (;;) {
+ *env = *nxt++;
+ if ((*env == '\0') && (*nxt == '\0'))
+ break;
+ ++env;
+ }
+ }
+ *++env = '\0';
+ }
+
+ if ((varval == NULL) || (*varval == '\0')) {
+ if (oldval < 0) {
+ pr_info("No assigned any value for %s\n", varname);
+ rcode++;
+ } else {
+ rcode = 0;
+ }
+ goto out;
+ }
+
+ /*
+ * Append new definition at the end
+ */
+ for (env = env_data; *env || *(env+1); ++env)
+ ;
+ if (env > env_data)
+ ++env;
+ /*
+ * Overflow when:
+ * "varname" + "=" + "val" +"\0\0" > ENV_SIZE - (env-env_data)
+ */
+ len = strlen(varname) + 2;
+ /* add '=' for first arg, ' ' for all others */
+ len += strlen(varval);
+ if (len > (&env_data[ENV_MAX_SIZE]-env)) {
+ printk(KERN_WARNING "## Warning: environment overflow, \"%s\" deleted\n",
+ varname);
+ rcode++;
+ goto out;
+ }
+ while ((*env = *varname++) != '\0')
+ env++;
+
+ *env = '=';
+ while ((*++env = *varval++) != '\0')
+ ;
+
+ /* end is marked with double '\0' */
+ *++env = '\0';
+
+ rcode = 0;
+
+out:
+
+ return rcode;
+}
+
+int is_persist(char *name)
+{
+ int i, len;
+ char *persistlist[]={"otp.", "ethaddr", "wmt.ethaddr.persist", "androidboot.serialno",
+ "btaddr", "wmt.btaddr.persist","pcba.serialno","serialnum","persist.", NULL};
+
+ for(i=0; persistlist[i] != NULL; i++){
+ len = strlen(persistlist[i]);
+ if(!strncmp(name, persistlist[i], len))
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * sync env2's persist to env1, then update to env1 and env2
+ */
+int sync_persist_env(struct env_t *env1, struct env_t *env2)
+{
+ int i;
+ int updated=0;
+ unsigned char name[MAX_NAME_SIZE] = {0};
+ unsigned char *val = NULL,*valbuf=NULL;
+ unsigned char *s;
+
+ valbuf = kzalloc(MAX_VALUE_SIZE,GFP_KERNEL);
+ if(!valbuf){
+ printk("alloc mem failed!\n");
+ return -ENOMEM;
+ }
+
+ for(s = env2->data; s < (env2->data+ENV_DATA_SIZE) && *s!='\0'; ){
+
+ if(is_persist(s)==0){
+ i=0;
+ while(*s != '=' && *s != '\0' && i < (sizeof(name)-1))
+ name[i++] = *s++;
+
+ name[i] = '\0';
+
+ i=0;
+ s++;//skip '='
+ val = valbuf;
+ while(*s != '\0')
+ val[i++] = *s++;
+
+ val[i] = '\0';
+ s++;
+ //printk("%s=%s\n",name,val);
+
+ if(search_env(ENV1,name)){
+ printk("insert %s=%s to env1\n",name,val);
+ insert_env(ENV1,name,val);
+ //updated ++;
+ }
+ }
+ else{
+ s += (strlen(s)+1);
+ }
+ }
+
+ //printk("sync %d otps to env1\n",updated);
+ save_env(ENV1,env1);
+ save_env(ENV2,env1);
+ memcpy(env2,env1,sizeof(struct env_t));
+ kfree(valbuf);
+
+ return 0;
+}
+
+
+/*
+ * sync and update env to SF
+ */
+static int update_env(int to_update)
+{
+ struct env_t *env1 = uboot_env->env[ENV1];
+ struct env_t *env2 = uboot_env->env[ENV2];
+
+ if(!to_update){
+ return 0;
+ }
+
+ if(uboot_env->env_readed)
+ return sync_persist_env(env1,env2);
+
+ return -EIO;
+}
+
+static int esync(void)
+{
+ int i;
+ int ret;
+ u32 crc1,crc2;
+ char *dest,*src;
+ struct env_t *env1,*env2;
+
+ /* copy env raw data */
+ for(i = 0; i < 2; i++){
+ dest = (char *)uboot_env->env[i];
+ src = (char *)(uboot_env->offset[i] + uboot_env->io_base);
+ memset(dest, 0x00, ENV_MAX_SIZE);
+ sf_copy_env(dest, src, ENV_MAX_SIZE);
+ }
+
+ env1 = uboot_env->env[ENV1];
+ crc1 = uboot_crc32(0, env1->data, ENV_DATA_SIZE);
+
+ env2 = uboot_env->env[ENV2];
+ crc2 = uboot_crc32(0, env2->data, ENV_DATA_SIZE);
+
+ printk("crc1:%08x,%08x; crc2:%08x,%08x\n", env1->crc,crc1,env2->crc,crc2);
+
+ if( crc1 == env1->crc && crc2 == env2->crc && crc1 == crc2){
+ printk("env1==env2\n");
+ }else if(crc1 != env1->crc && crc2 == env2->crc){
+ printk("env2->env1\n");
+ return save_env(ENV1, env2);
+ }else if(crc1 == env1->crc && crc2 != env2->crc ){
+ printk("env1->env2\n");
+ return save_env(ENV2, env1);
+ }else if(crc1 == env1->crc && crc2 == env2->crc && crc1 != crc2 ){
+ printk("env1<->env2\n");
+ return sync_persist_env(env1,env2);
+ }else{
+ printk("env1,env2 invalid\n");
+ }
+
+ return 0;
+}
+
+/* Get the system parameter if existed.
+ *
+ * - varname: parameter name
+ * - varval : a buffer to store the parameter
+ * - varlen : the buffer size for the varval pointer
+ *
+ * return 0 if success.
+ */
+int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen)
+{
+ int i, j, k, nxt = 0;
+ int rcode = 0;
+
+ int ret = down_interruptible(&s_wmt_env_lock);
+ if (ret) {
+ printk(KERN_WARNING "lock s_wmt_env_lock error: %d\n", ret);
+ return -EAGAIN;
+ }
+
+ if (env_init_if_needed()){
+ rcode = -EIO;
+ goto out;
+ }
+
+ k = -1;
+ i = 0;
+ for (j = 0; env_get_char(ENV1, j) != '\0'; j = nxt+1) {
+
+ for (nxt = j; env_get_char(ENV1, nxt) != '\0'; ++nxt)
+ ;
+ k = envmatch(ENV1, (unsigned char *)varname, j);
+ if (k < 0)
+ continue;
+ while (k < nxt && i < *varlen)
+ varval[i++] = env_get_char(ENV1, k++);
+ if( k == nxt)
+ varval[i] = '\0';
+ break;
+ }
+
+ if (k < nxt && k > 0) {
+ printk(KERN_WARNING "## Warning: \"%s\" size(%d) exceed buffer size(%d)\n",
+ varname, i+(nxt-k), *varlen);
+ *varlen = i+(nxt-k);
+ rcode = 10;
+ goto out;
+ }
+
+ if (k < 0) {
+ rcode++;
+ }
+out:
+ up(&s_wmt_env_lock);
+ return rcode;
+}
+EXPORT_SYMBOL_GPL(wmt_getsyspara);
+
+/* Set the system parameter.
+ *
+ * - varname: parameter name
+ * - varval : the buffer to store the system parameter value for setting.
+ *
+ * If the pointer is NULL and the system parameter is existed,
+ * then the system parameter will be clear.
+ *
+ * return 0 if success.
+ */
+int wmt_setsyspara(char *name, char *varval)
+{
+ int len, oldval;
+ int rcode = 0;
+ unsigned char *env, *nxt = NULL;
+ unsigned char *env_data;
+ int is_otp_env;
+ int do_wsf = 1;
+ unsigned char *varname = name;
+
+ if(*varname == '\0')
+ return -EINVAL;
+
+ int ret = down_interruptible(&s_wmt_env_lock);
+ if (ret) {
+ printk(KERN_WARNING "lock s_wmt_env_lock error: %d\n", ret);
+ return -EAGAIN;
+ }
+
+ /*
+ * parameter name start with '~' is store in buf
+ */
+ if(*varname == '~'){
+ do_wsf = 0;
+ varname++;
+ }
+
+ if (env_init_if_needed()){
+ rcode = -EIO;
+ goto out;
+ }
+
+ if(!strcmp(varname,"esync")){
+ rcode = esync();
+ goto out;
+ }
+
+ is_otp_env = !strncmp(varname, "otp.", 4);
+
+ if( !is_otp_env && wmt_is_secure_enabled() ) {
+ //check white list for u-boot env
+ int i;
+ for( i = 0; env_white_list[i]; i++) {
+ if( !strcmp(varname, env_white_list[i]))
+ break;
+ }
+ if(!env_white_list[i]) {
+ printk("Not in env white list, disable write <%s>\n", varname);
+ rcode = -EPERM;
+ goto out;
+ }
+ }
+
+ if (strcmp(varname, "boot-method") == 0) {
+ if( strcmp(varval, "boot-nand-ota-normal") &&
+ strcmp(varval, "boot-nand-ota-recovery")&&
+ strcmp(varval, "boot-nand-otz-normal") &&
+ strcmp(varval, "boot-nand-otz-recovery")) {
+ printk("boot-method unsupported varval: %s\n", varval);
+ rcode = -EINVAL;
+ goto out;
+ }
+ }
+
+ env_data = uboot_env->env[ENV1]->data;
+
+ /*
+ * search if variable with this name already exists
+ */
+ oldval = -1;
+ for (env = env_data; *env; env = nxt+1) {
+ for (nxt = env; *nxt; ++nxt)
+ ;
+ oldval = envmatch(ENV1, (unsigned char *)varname, env - env_data);
+ if (oldval >= 0)
+ break;
+ }
+
+ /*
+ * Delete any existing definition
+ */
+ if (oldval >= 0) {
+ /* otp env can not overwrite */
+ if (is_otp_env) {
+ rcode = -EEXIST;
+ printk("Warning:OTP env can not overwrite!\n");
+ goto out;
+ }
+
+ if (*++nxt == '\0') {
+ if (env > env_data)
+ env--;
+ else
+ *env = '\0';
+ } else {
+ for (;;) {
+ *env = *nxt++;
+ if ((*env == '\0') && (*nxt == '\0'))
+ break;
+ ++env;
+ }
+ }
+ *++env = '\0';
+ }
+
+ if ((varval == NULL) || (*varval == '\0')) {
+ if (oldval < 0) {
+ pr_info("No assigned any value for %s\n", varname);
+ rcode++;
+ } else {
+ /*
+ * varname will be clear
+ */
+ pr_info("Delete environment variable: %s\n", varname);
+ if (update_env(do_wsf))
+ rcode++;
+ else
+ rcode = 0;
+ }
+ goto out;
+ }
+
+ /*
+ * Append new definition at the end
+ */
+ for (env = env_data; *env || *(env+1); ++env)
+ ;
+ if (env > env_data)
+ ++env;
+ /*
+ * Overflow when:
+ * "varname" + "=" + "val" +"\0\0" > ENV_SIZE - (env-env_data)
+ */
+ len = strlen(varname) + 2;
+ /* add '=' for first arg, ' ' for all others */
+ len += strlen(varval);
+ if (len > (&env_data[ENV_MAX_SIZE]-env)) {
+ printk(KERN_WARNING "## Warning: environment overflow, \"%s\" deleted\n",
+ varname);
+ rcode++;
+ goto out;
+ }
+ while ((*env = *varname++) != '\0')
+ env++;
+
+ *env = '=';
+ while ((*++env = *varval++) != '\0')
+ ;
+
+ /* end is marked with double '\0' */
+ *++env = '\0';
+
+ if (update_env(do_wsf))
+ rcode++;
+ else
+ rcode = 0;
+
+out:
+ up(&s_wmt_env_lock);
+ return rcode;
+}
+EXPORT_SYMBOL_GPL(wmt_setsyspara);
+
+/*
+ * Get the WMT SoC chipid & bondingid.
+ */
+int wmt_getsocinfo(unsigned int *chipid, unsigned int *bondingid)
+{
+ *chipid = SCC_CHIP_ID_ADDR;
+ *bondingid = BONDING_OPTION_4BYTE_ADDR;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wmt_getsocinfo);
+
+int wmt_is_secure_enabled(void)
+{
+ static int secure_enabled = 0;
+
+ if (secure_enabled == 0) {
+ char value[512] = {'\0',};
+ int len = 511;
+ if (wmt_getsyspara("otp.rsa.pem", value, &len) == 0 && len > 0) {
+ secure_enabled = 1;
+ }
+ else {
+ secure_enabled = -1;
+ }
+ }
+ return secure_enabled == 1 ? 1 : 0;
+}
+EXPORT_SYMBOL_GPL(wmt_is_secure_enabled);
+
+static int do_rsa(uint8_t *sig_data, size_t sig_len, uint8_t *publickey,
+ uint8_t *hash_signature)
+{
+ uint8_t out_buf[128], tmp;
+ int ret = 0;
+ int i, j, k;
+
+ ret = rsa_check((unsigned int)publickey, strlen(publickey),
+ (uint32_t)sig_data, sig_len, out_buf);
+ if (ret) {
+ printk("decode signature fail\n");
+ return 2;
+ }
+
+ for (i = 0, j = 0; i < 64; i=i+2,j++) {
+ tmp = 0;
+ for (k = 0; k < 2; k++) {
+ if (out_buf[i+k] == '0')
+ tmp += ((k == 0) ?(0<<4):0);
+ else if (out_buf[i+k] == '1')
+ tmp += ((k == 0) ?(1<<4):1);
+ else if (out_buf[i+k] == '2')
+ tmp += ((k == 0) ?(2<<4):2);
+ else if (out_buf[i+k] == '3')
+ tmp += ((k == 0) ?(3<<4):3);
+ else if (out_buf[i+k] == '4')
+ tmp += ((k == 0) ?(4<<4):4);
+ else if (out_buf[i+k] == '5')
+ tmp += ((k == 0) ?(5<<4):5);
+ else if (out_buf[i+k] == '6')
+ tmp += ((k == 0) ?(6<<4):6);
+ else if (out_buf[i+k] == '7')
+ tmp += ((k == 0) ?(7<<4):7);
+ else if (out_buf[i+k] == '8')
+ tmp += ((k == 0) ?(8<<4):8);
+ else if (out_buf[i+k] == '9')
+ tmp += ((k == 0) ?(9<<4):9);
+ else if (out_buf[i+k] == 'a')
+ tmp += ((k == 0) ?(0xa<<4):0xa);
+ else if (out_buf[i+k] == 'b')
+ tmp += ((k == 0) ?(0xb<<4):0xb);
+ else if (out_buf[i+k] == 'c')
+ tmp += ((k == 0) ?(0xc<<4):0xc);
+ else if (out_buf[i+k] == 'd')
+ tmp += ((k == 0) ?(0xd<<4):0xd);
+ else if (out_buf[i+k] == 'e')
+ tmp += ((k == 0) ?(0xe<<4):0xe);
+ else if (out_buf[i+k] == 'f')
+ tmp += ((k == 0) ?(0xf<<4):0xf);
+ else {
+ printk("change from character to digit fail out_buf[%d]=%c\n", i, out_buf[i]);
+ ret = 3;
+ break;
+ }
+ }
+ if (ret == 3)
+ break;
+ hash_signature[j] = tmp;
+ }
+
+ return ret;
+}
+
+static int do_hash(uint8_t *buf, size_t len, unsigned char sha256sum[32])
+{
+ sha256_context ctx;
+
+ sha256_starts(&ctx);
+
+ sha256_update(&ctx, buf, len);
+
+ sha256_finish(&ctx, sha256sum);
+
+#ifdef DEBUG
+ {
+ int j;
+ for (j = 0; j < 32; j++) {
+ printk( "%02x", sha256sum[j] );
+ }
+ printk("\n");
+ }
+#endif
+ return 0;
+}
+
+int wmt_write_signed_image(struct write_signed_image *w)
+{
+ uint8_t hash_sig[64], hash_img[32];
+ char publickey[400];
+ size_t len = sizeof(publickey);
+ uint32_t offset;
+ size_t size;
+ void *io_base;
+ int rc = 0, i;
+
+
+ if (wmt_getsyspara("otp.rsa.pem", publickey, &len) == 0) {
+
+ if (do_rsa(w->sig_data, w->sig_len, publickey, hash_sig)) {
+ printk("do rsa failed\n");
+ return -1;
+ }
+
+
+
+ if (do_hash(w->img_data, w->img_len, hash_img)) {
+ printk("do hash failed\n");
+ return -2;
+ }
+
+ if (memcmp(hash_sig, hash_img, 32)) {
+ for (i = 0; i < 32; i++)
+ printk("%2.2x", hash_sig[i]);
+ printk("\n");
+ for (i = 0; i < 32; i++)
+ printk("%2.2x", hash_img[i]);
+ printk("\n image check fail\n");
+ return -3;
+ }
+ pr_info("Decrypto signature success\n");
+ } else
+ pr_info("otp.rsa.pem not found\n");
+
+ // update
+
+ switch (w->type) {
+ case SIGNED_IMAGE_TYPE_WLOAD: // "w-load-SF",
+ offset = 0x00070000;
+ size = 0x00010000;
+ break;
+ case SIGNED_IMAGE_TYPE_UBOOT: // "u-boot-SF",
+ offset = 0x00000000;
+ size = 0x00050000;
+ break;
+ case SIGNED_IMAGE_TYPE_UBOOT_ENV: // "u-boot env. cfg. 1-SF",
+ offset = 0x00050000;
+ size = 0x00010000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (w->img_len > size) {
+ printk(" max size 0x%x\n", size);
+ return -E2BIG;
+ }
+
+ rc = down_interruptible(&s_wmt_env_lock);
+ if (rc) {
+ printk(KERN_WARNING "lock s_wmt_env_lock error: %d\n", rc);
+ return -EAGAIN;
+ }
+
+ // Erase
+ for (len = 0; len < size; len += 0x10000) {
+ printk(" Erase flash 0x%x\n", offset + len);
+
+ rc = spi_flash_sector_erase(offset + len,
+ (struct sfreg_t *)SF_BASE_ADDR);
+ if (rc != ERR_OK) {
+ pr_err("spi_flash_sector_erase failed\n");
+ rc = -EIO;
+ goto out;
+ }
+ }
+
+ // Write
+ io_base = uboot_env->io_base;
+
+ spi_flash_sector_write(((struct sfreg_t *)SF_BASE_ADDR),
+ io_base, offset, w->img_len, w->img_data);
+
+out:
+ up(&s_wmt_env_lock);
+ return rc;
+}
+
+
+/*
+ * reload the env from partition.
+ * After Hibernation restore, call this function since
+ * the env may has been changed before restoration.
+ * This function is considered only be called by hibernation related code.
+ * Do not call this function from different kernel thread at the same time.
+ */
+int env_cache_flush(void)
+{
+ int i;
+ int ret;
+ u32 crc1,crc2;
+ char *dest,*src;
+ struct env_t *env1,*env2;
+
+ /* copy env raw data */
+ for(i = 0; i < 2; i++){
+ dest = (char *)uboot_env->env[i];
+ src = (char *)(uboot_env->offset[i] + uboot_env->io_base);
+ memset(dest, 0x00, ENV_MAX_SIZE);
+ sf_copy_env(dest, src, ENV_MAX_SIZE);
+ }
+
+ env1 = uboot_env->env[ENV1];
+ crc1 = uboot_crc32(0, env1->data, ENV_DATA_SIZE);
+
+ env2 = uboot_env->env[ENV2];
+ crc2 = uboot_crc32(0, env2->data, ENV_DATA_SIZE);
+
+ if(crc1 != env1->crc){
+ printk("Error:env1 crc error!");
+ return 1;
+ }
+
+ if(crc2 != env2->crc)
+ printk("Warning:env2 crc error!");
+
+ return 0;
+}