stm32f4xx_eedata: define & implement eedata api

also migrate aes key lookup to it

Change-Id: I3574acedce3747d8d848b48e9cbc9c01e1a4e304
diff --git a/firmware/inc/eeData.h b/firmware/inc/eeData.h
new file mode 100644
index 0000000..64b8185
--- /dev/null
+++ b/firmware/inc/eeData.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef _EEDATA_H_
+#define _EEDATA_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/*
+ * EEDATA allows storage of data in a persistent area that survives reboots and OS updates.
+ * Each data piece has a name and stores 0..EE_DATA_LEN_MAX bytes of data. The name is a
+ * non-zero number in the range 0..EE_DATA_NAME_MAX - 1. All names below EE_DATA_FIRST_USER
+ * are reserved for OS purposes and are not accessible using the external-app-visible API.
+ * To store an EEDATA item, use eeDataSet(). Setting the buffer to NULL will delete an
+ * existing item and not replace it. Otherwise an item is replaced. Return value is success
+ * (deleting a non-existent item always suceeds). You can use eeDataGet() to get items. It
+ * will return true if an item exists. If called with buf set to NULL and szP not NULL,
+ * *szP will be filled with its size. Else if buf and szP are both not NULL, up to *szP
+ * bytes will be stored into buf, and *szP will be updated with the number of bytes written.
+ * True is returned if the data item exists at all, else false is. For encryption keys, we
+ * [ab]use eeDataGetAllVersions to get all keys (as each has the same name).
+ */
+
+
+
+#define EE_DATA_NAME_MAX   0x000FFFFF
+#define EE_DATA_LEN_MAX    0x00000FFF //in bytes
+#define EE_DATA_FIRST_USER 0x00000100
+
+
+bool eeDataGet(uint32_t name, void *buf, uint32_t *szP);
+bool eeDataSet(uint32_t name, const void *buf, uint32_t len);
+
+//allow getting old "versions". Set state to NULL initially, call till you get false
+bool eeDataGetAllVersions(uint32_t name, void *buf, uint32_t *szP, void **stateP);
+bool eeDataEraseOldVersion(uint32_t name, void *state); //state == state BEFORE call to eeDataGetAllVersions that found the version you want gone
+
+//predefined key types
+
+#define EE_DATA_NAME_ENCR_KEY            1
+
+
+
+#endif
+
diff --git a/firmware/inc/platform/stm32f4xx/bl.h b/firmware/inc/platform/stm32f4xx/bl.h
index cd43fca..9824493 100644
--- a/firmware/inc/platform/stm32f4xx/bl.h
+++ b/firmware/inc/platform/stm32f4xx/bl.h
@@ -80,6 +80,7 @@
     //flash
     bool            (*blProgramShared)(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t key1, uint32_t key2);
     bool            (*blEraseShared)(uint32_t key1, uint32_t key2);
+    bool            (*blProgramEe)(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t key1, uint32_t key2);
 
     //security data
     const uint32_t* (*blGetPubKeysInfo)(uint32_t *numKeys);
diff --git a/firmware/inc/platform/stm32f4xx/eeData.h b/firmware/inc/platform/stm32f4xx/eeData.h
new file mode 100644
index 0000000..6cba150
--- /dev/null
+++ b/firmware/inc/platform/stm32f4xx/eeData.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef _STM32F4xx_EEDATA_H_
+#define _STM32F4xx_EEDATA_H_
+
+#include <eeData.h>
+#include <seos.h>
+
+struct Stm32f4xxEedataHdr {
+    uint32_t info;
+};
+
+struct Stm32f4xxEedataEncrKey {
+    struct Stm32f4xxEedataHdr hdr;
+    struct SeosEedataEncrKeyData data;
+} __attribute__((packed));
+
+
+#define PREPOPULATED_ENCR_KEY(name, keyid, ...) \
+    const struct Stm32f4xxEedataEncrKey __attribute__ ((section (".eedata"))) __EE__ ## name = { { EE_DATA_NAME_ENCR_KEY + sizeof(struct SeosEedataEncrKeyData) * (EE_DATA_NAME_MAX + 1)}, {keyid, {__VA_ARGS__}}}
+
+
+
+#endif
diff --git a/firmware/inc/platform/stm32f4xx/plat.h b/firmware/inc/platform/stm32f4xx/plat.h
index fdefbcd..6ffb0af 100644
--- a/firmware/inc/platform/stm32f4xx/plat.h
+++ b/firmware/inc/platform/stm32f4xx/plat.h
@@ -39,17 +39,6 @@
     Stm32sleepDevNum,  //must be last always, and must be <= PLAT_MAX_SLEEP_DEVS
 };
 
-struct StmPlatEeDataGeneric {
-    uint32_t eeDataType : 20;
-    uint32_t eeDataLen  : 12; // not incl header
-} __attribute__((packed));
-
-struct StmPlatEeDataEncrKey {
-    struct StmPlatEeDataGeneric hdr;
-    uint64_t keyID;
-    uint8_t key[32];
-} __attribute__((packed));
-
 static inline const struct AppHdr* platGetInternalAppList(uint32_t *numAppsP)
 {
     extern const struct AppHdr __internal_app_start, __internal_app_end;
@@ -70,8 +59,6 @@
 //used for dropbox
 void* platGetPersistentRamStore(uint32_t *bytes);
 
-#define PREPOPULATED_ENCR_KEY(name, keyid, ...) \
-    const struct StmPlatEeDataEncrKey __attribute__ ((section (".eedata"))) __EE__ ## name = { { EE_DATA_TYPE_ENCR_KEY, sizeof(struct StmPlatEeDataEncrKey) - sizeof(struct StmPlatEeDataGeneric)}, keyid, {__VA_ARGS__}}
 
 #ifdef __cplusplus
 }
diff --git a/firmware/inc/seos.h b/firmware/inc/seos.h
index b2554cd..9f6b1b1 100644
--- a/firmware/inc/seos.h
+++ b/firmware/inc/seos.h
@@ -41,8 +41,6 @@
 
 #define OS_VER                           0x0000
 
-#define EE_DATA_TYPE_ENCR_KEY            1
-
 #define ENCR_KEY_GOOGLE_PREPOPULATED     1 // our key ID is 1
 
 #define FIRST_VALID_TID                  0x00000001
@@ -105,6 +103,11 @@
 
 typedef void (*EventFreeF)(void* event);
 
+struct SeosEedataEncrKeyData {
+    uint64_t keyID;
+    uint8_t key[32];
+} __attribute__((packed));
+
 /* ==== ABOUT THE "urgent" FLAG ====
  *
  * Do not set "urgent" unless you understand all the repercussions! What repercussions you might ask?
diff --git a/firmware/misc/platform/stm32f4xx/Makefile b/firmware/misc/platform/stm32f4xx/Makefile
index 3c7662e..37c9aba 100644
--- a/firmware/misc/platform/stm32f4xx/Makefile
+++ b/firmware/misc/platform/stm32f4xx/Makefile
@@ -49,6 +49,7 @@
 	src/platform/$(PLATFORM)/crc.c \
 	src/platform/$(PLATFORM)/hostIntf.c \
 	src/platform/$(PLATFORM)/apInt.c \
+	src/platform/$(PLATFORM)/eeData.c
 
 #extra deps
 DEPS += $(wildcard inc/platform/$(PLATFORM)/*.h)
diff --git a/firmware/src/nanohubCommand.c b/firmware/src/nanohubCommand.c
index d6323bd..b91b5f0 100644
--- a/firmware/src/nanohubCommand.c
+++ b/firmware/src/nanohubCommand.c
@@ -26,6 +26,7 @@
 #include <hostIntf_priv.h>
 #include <nanohubCommand.h>
 #include <nanohubPacket.h>
+#include <eeData.h>
 #include <seos.h>
 #include <util.h>
 #include <mpu.h>
@@ -141,23 +142,19 @@
 
 static AppSecErr aesKeyAccessCbk(uint64_t keyIdx, void *keyBuf)
 {
-    extern const struct StmPlatEeDataGeneric __eedata_start;
-    extern char __eedata_end[];
-    const struct StmPlatEeDataGeneric *hdr;
-    const struct StmPlatEeDataEncrKey *key;
+    struct SeosEedataEncrKeyData kd;
+    void *state = NULL;
 
-    hdr = &__eedata_start;
-    while (((uintptr_t)&__eedata_end) - ((uintptr_t)hdr) >= sizeof(struct StmPlatEeDataGeneric) && hdr->eeDataType != 0xFFFFF) {
-        switch (hdr->eeDataType) {
-        case EE_DATA_TYPE_ENCR_KEY:
-            key = (const struct StmPlatEeDataEncrKey *)hdr;
-            if (key->keyID == keyIdx) {
-                memcpy(keyBuf, key->key, sizeof(key->key));
-                return APP_SEC_NO_ERROR;
-            }
+    while(1) {
+        uint32_t sz = sizeof(struct SeosEedataEncrKeyData);
+
+        if (!eeDataGetAllVersions(EE_DATA_NAME_ENCR_KEY, &kd, &sz, &state))
             break;
+
+        if (sz == sizeof(struct SeosEedataEncrKeyData) && kd.keyID == keyIdx) {
+            memcpy(keyBuf, kd.key, sizeof(kd.key));
+            return APP_SEC_NO_ERROR;
         }
-        hdr = (const struct StmPlatEeDataGeneric*)(((((uintptr_t)hdr) + sizeof(struct StmPlatEeDataGeneric) + hdr->eeDataLen) + 3) &~ 3);
     }
 
     return APP_SEC_KEY_NOT_FOUND;
diff --git a/firmware/src/platform/stm32f4xx/bl.c b/firmware/src/platform/stm32f4xx/bl.c
index bdb1b57..916ad99 100644
--- a/firmware/src/platform/stm32f4xx/bl.c
+++ b/firmware/src/platform/stm32f4xx/bl.c
@@ -506,7 +506,7 @@
 }
 
 BOOTLOADER
-static bool blExtApiProgramSharedArea(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t key1, uint32_t key2)
+static bool blExtApiProgramTypedArea(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t key1, uint32_t key2, uint32_t type)
 {
     const uint32_t sector_cnt = sizeof(mBlFlashTable) / sizeof(struct blFlashTable);
     uint32_t i;
@@ -517,7 +517,7 @@
              dst < (mBlFlashTable[i].address + mBlFlashTable[i].length)) ||
             (dst < mBlFlashTable[i].address &&
              (dst + length > mBlFlashTable[i].address))) {
-            if (mBlFlashTable[i].type != BL_FLASH_SHARED)
+            if (mBlFlashTable[i].type != type)
                 return false;
         }
     }
@@ -526,6 +526,18 @@
 }
 
 BOOTLOADER
+static bool blExtApiProgramSharedArea(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t key1, uint32_t key2)
+{
+    return blExtApiProgramTypedArea(dst, src, length, key1, key2, BL_FLASH_SHARED);
+}
+
+BOOTLOADER
+static bool blExtApiProgramEe(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t key1, uint32_t key2)
+{
+    return blExtApiProgramTypedArea(dst, src, length, key1, key2, BL_FLASH_EEDATA);
+}
+
+BOOTLOADER
 static bool blExtApiEraseSharedArea(uint32_t key1, uint32_t key2)
 {
     struct StmFlash *flash = (struct StmFlash *)FLASH_BASE;
@@ -650,6 +662,7 @@
     .blGetSnum = &blExtApiGetSnum,
     .blProgramShared = &blExtApiProgramSharedArea,
     .blEraseShared = &blExtApiEraseSharedArea,
+    .blProgramEe = &blExtApiProgramEe,
     .blGetPubKeysInfo = &blExtApiGetRsaKeyInfo,
     .blRsaPubOpIterative = &_rsaPubOpIterative,
     .blSha2init = &_sha2init,
diff --git a/firmware/src/platform/stm32f4xx/eeData.c b/firmware/src/platform/stm32f4xx/eeData.c
new file mode 100644
index 0000000..bde9f9f
--- /dev/null
+++ b/firmware/src/platform/stm32f4xx/eeData.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 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 <plat/inc/bl.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdint.h>
+#include <eeData.h>
+
+
+extern uint32_t __eedata_start[], __eedata_end[];
+
+//STM32F4xx eedata stores data in 4-byte aligned chunks
+
+static void* eeFind(uint32_t nameToFind, uint32_t startOffset, bool findFirst, uint32_t *szP)
+{
+    uint32_t *p = __eedata_start + startOffset;
+    void *foundData = NULL;
+
+    //find the last incarnation of "name" in flash area
+    while (p < __eedata_end) {
+        uint32_t info = *p++;
+        uint32_t name = info & EE_DATA_NAME_MAX;
+        uint32_t sz = info / (EE_DATA_NAME_MAX + 1);
+        void *data = p;
+
+        //skip over to next data chunk header
+        p += (sz + 3) / 4;
+
+        //check for a match
+        if (nameToFind == name) {
+            *szP = sz;
+            foundData = data;
+
+            if (findFirst)
+                break;
+        }
+
+        //check for ending condition (name == max)
+        if (name == EE_DATA_NAME_MAX)
+            break;
+    }
+
+    return foundData;
+}
+
+static bool eeIsValidName(uint32_t name)
+{
+    return name && name < EE_DATA_NAME_MAX;
+}
+
+static bool eeDataGetEx(uint32_t name, uint32_t *offsetP, bool first, void *buf, uint32_t *szP)
+{
+    uint32_t sz = 0;
+    void *data;
+
+    if (!eeIsValidName(name))
+        return false;
+
+    //find the data item
+    data = eeFind(name, *offsetP, first, &sz);
+    if (!data)
+        return false;
+
+    if (buf && szP) {    //get the data
+        if (sz > *szP)
+            sz = *szP;
+        *szP = sz;
+        memcpy(buf, data, sz);
+    }
+    else if (szP)        //get size
+        *szP = sz;
+
+    *offsetP = (uint32_t)data + ((sz + 3) &~ 3);
+
+    return true;
+}
+
+bool eeDataGet(uint32_t name, void *buf, uint32_t *szP)
+{
+    uint32_t offset = 0;
+
+    return eeDataGetEx(name, &offset, false, buf, szP);
+}
+
+bool eeDataGetAllVersions(uint32_t name, void *buf, uint32_t *szP, void **stateP)
+{
+    uint32_t offset = *(uint32_t*)stateP;
+    bool ret;
+
+    ret = eeDataGetEx(name, &offset, true, buf, szP);
+    *(uint32_t*)stateP = offset;
+
+    return ret;
+}
+
+static bool eeWrite(void *dst, const void *src, uint32_t len)
+{
+    return BL.blProgramEe(dst, src, len, BL_FLASH_KEY1, BL_FLASH_KEY2);
+}
+
+bool eeDataSet(uint32_t name, const void *buf, uint32_t len)
+{
+    uint32_t sz, effectiveSz, info = name + len * (EE_DATA_NAME_MAX + 1);
+    bool ret = true;
+    void *space;
+
+    if (!eeIsValidName(name))
+        return false;
+
+    //find the empty space at the end of everything and make sure it is really empty (size == EE_DATA_LEN_MAX)
+    space = eeFind(EE_DATA_NAME_MAX, 0, false, &sz);
+    if (!space || sz != EE_DATA_LEN_MAX)
+        return false;
+
+    //calculate effective size
+    effectiveSz = (len + 3) &~ 3;
+
+    //verify we have the space
+    if ((uint8_t*)__eedata_end - (uint8_t*)space < effectiveSz)
+        return false;
+
+    //write it in
+    ret = eeWrite(((uint32_t*)space) - 1, &info, sizeof(info)) && ret;
+    ret = eeWrite(space, buf, len) && ret;
+
+    return ret;
+}
+
+bool eeDataEraseOldVersion(uint32_t name, void *state)
+{
+    uint32_t v = *(uint32_t*)state;
+
+    if (!eeIsValidName(name))
+        return false;
+
+    //verify name
+    if ((v & EE_DATA_NAME_MAX) != name)
+        return false;
+
+    //clear name
+    v &=~ EE_DATA_NAME_MAX;
+
+    //store result
+    return eeWrite(state, &v, sizeof(v));
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/firmware/src/seos.c b/firmware/src/seos.c
index 95e7fdc..4f6bfda 100644
--- a/firmware/src/seos.c
+++ b/firmware/src/seos.c
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <plat/inc/eeData.h>
 #include <plat/inc/plat.h>
 #include <plat/inc/bl.h>
 #include <platform.h>