1 /*
2  * Copyright (C) 2016 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 <plat/inc/bl.h>
18 #include <stdbool.h>
19 #include <string.h>
20 #include <stdint.h>
21 #include <eeData.h>
22 
23 extern uint32_t __eedata_start[], __eedata_end[];
24 
25 //STM32F4xx eedata stores data in 4-byte aligned chunks
26 
eeFind(uint32_t nameToFind,uint32_t * offset,bool findFirst,uint32_t * szP)27 static void* eeFind(uint32_t nameToFind, uint32_t *offset, bool findFirst, uint32_t *szP)
28 {
29     uint32_t *p = __eedata_start + (offset ? *offset : 0);
30     void *foundData = NULL;
31 
32     //find the last incarnation of "name" in flash area
33     while (p < __eedata_end) {
34         uint32_t info = *p++;
35         uint32_t name = info & EE_DATA_NAME_MAX;
36         uint32_t sz = info / (EE_DATA_NAME_MAX + 1);
37         void *data = p;
38 
39         //skip over to next data chunk header
40         p += (sz + 3) / 4;
41 
42         //check for a match
43         if (nameToFind == name) {
44             *szP = sz;
45             foundData = data;
46 
47             if (findFirst)
48                 break;
49         }
50 
51         //check for ending condition (name == max)
52         if (name == EE_DATA_NAME_MAX)
53             break;
54     }
55 
56     if (offset)
57         *offset = p - __eedata_start;
58 
59     return foundData;
60 }
61 
eeIsValidName(uint32_t name)62 static bool eeIsValidName(uint32_t name)
63 {
64     return name && name < EE_DATA_NAME_MAX;
65 }
66 
eeDataGetEx(uint32_t name,uint32_t * offsetP,bool first,void * buf,uint32_t * szP)67 static void *eeDataGetEx(uint32_t name, uint32_t *offsetP, bool first, void *buf, uint32_t *szP)
68 {
69     uint32_t sz = 0;
70     void *data;
71 
72     if (!eeIsValidName(name))
73         return false;
74 
75     //find the data item
76     data = eeFind(name, offsetP, first, &sz);
77     if (!data)
78         return NULL;
79 
80     if (buf && szP) {    //get the data
81         if (sz > *szP)
82             sz = *szP;
83         *szP = sz;
84         memcpy(buf, data, sz);
85     }
86     else if (szP)        //get size
87         *szP = sz;
88 
89     return (uint32_t*)data - 1;
90 }
91 
eeDataGet(uint32_t name,void * buf,uint32_t * szP)92 bool eeDataGet(uint32_t name, void *buf, uint32_t *szP)
93 {
94     uint32_t offset = 0;
95 
96     return eeDataGetEx(name, &offset, false, buf, szP) != NULL;
97 }
98 
eeDataGetAllVersions(uint32_t name,void * buf,uint32_t * szP,void ** stateP)99 void *eeDataGetAllVersions(uint32_t name, void *buf, uint32_t *szP, void **stateP)
100 {
101     uint32_t offset = *(uint32_t*)stateP;
102     void *addr = eeDataGetEx(name, &offset, true, buf, szP);
103     *(uint32_t*)stateP = offset;
104     return addr;
105 }
106 
eeWrite(void * dst,const void * src,uint32_t len)107 static bool eeWrite(void *dst, const void *src, uint32_t len)
108 {
109     return BL.blProgramEe(dst, src, len, BL_FLASH_KEY1, BL_FLASH_KEY2);
110 }
111 
eeDataSet(uint32_t name,const void * buf,uint32_t len)112 bool eeDataSet(uint32_t name, const void *buf, uint32_t len)
113 {
114     uint32_t sz, effectiveSz, info = name + len * (EE_DATA_NAME_MAX + 1);
115     bool ret = true;
116     void *space;
117 
118     if (!eeIsValidName(name))
119         return false;
120 
121     //find the empty space at the end of everything and make sure it is really empty (size == EE_DATA_LEN_MAX)
122     space = eeFind(EE_DATA_NAME_MAX, NULL, false, &sz);
123     if (!space || sz != EE_DATA_LEN_MAX)
124         return false;
125 
126     //calculate effective size
127     effectiveSz = (len + 3) &~ 3;
128 
129     //verify we have the space
130     if ((uint8_t*)__eedata_end - (uint8_t*)space < effectiveSz)
131         return false;
132 
133     //write it in
134     ret = eeWrite(((uint32_t*)space) - 1, &info, sizeof(info)) && ret;
135     ret = eeWrite(space, buf, len) && ret;
136 
137     return ret;
138 }
139 
eeDataEraseOldVersion(uint32_t name,void * vaddr)140 bool eeDataEraseOldVersion(uint32_t name, void *vaddr)
141 {
142     uint32_t *addr = (uint32_t*)vaddr;
143     uint32_t v;
144 
145     // sanity check
146     if (!eeIsValidName(name) || addr < __eedata_start || addr >= (__eedata_end - 1))
147         return false;
148 
149     v = *addr;
150 
151     //verify name
152     if ((v & EE_DATA_NAME_MAX) != name)
153         return false;
154 
155     //clear name
156     v &=~ EE_DATA_NAME_MAX;
157 
158     //store result
159     return eeWrite(addr, &v, sizeof(v));
160 }
161