summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeer Chen <pchen@nvidia.com>2011-01-18 21:34:18 -0500
committerAllen Martin <amartin@nvidia.com>2011-01-25 12:51:58 -0800
commit8d782eec336359bb3a694e1a71b85cb3f0a3440f (patch)
tree692c09140e693f3d2078b9623a25cbab7e39ef5c
downloadnvidia-cbootimage-8d782eec336359bb3a694e1a71b85cb3f0a3440f.tar.gz
tegra tools: add the cbootimage for google request
cbootimage is a tool used to combine binary .bct, bootloader and google's component to a spi rom image file. Change-Id: I25b6fee13d7449fc83ec3802b79cbbbcaae54494
-rw-r--r--system/cbootimage/GNUmakefile20
-rw-r--r--system/cbootimage/aes_ref.c330
-rw-r--r--system/cbootimage/cbootimage.c258
-rw-r--r--system/cbootimage/cbootimage.h141
-rw-r--r--system/cbootimage/crypto.c303
-rw-r--r--system/cbootimage/crypto.h50
-rw-r--r--system/cbootimage/data_layout.c1027
-rw-r--r--system/cbootimage/data_layout.h56
-rw-r--r--system/cbootimage/nvaes_ref.h37
-rw-r--r--system/cbootimage/nvbctlib.h126
-rw-r--r--system/cbootimage/nvbctlib_ap20.c282
-rw-r--r--system/cbootimage/nvboot_bct.h151
-rw-r--r--system/cbootimage/parse.c527
-rw-r--r--system/cbootimage/parse.h74
-rw-r--r--system/cbootimage/set.c306
-rw-r--r--system/cbootimage/set.h81
16 files changed, 3769 insertions, 0 deletions
diff --git a/system/cbootimage/GNUmakefile b/system/cbootimage/GNUmakefile
new file mode 100644
index 0000000..6233fcd
--- /dev/null
+++ b/system/cbootimage/GNUmakefile
@@ -0,0 +1,20 @@
+C_FILES :=
+C_FILES += nvbctlib_ap20.c
+C_FILES += cbootimage.c
+C_FILES += data_layout.c
+C_FILES += parse.c
+C_FILES += set.c
+C_FILES += crypto.c
+C_FILES += aes_ref.c
+
+OBJS := $(patsubst %.c,%.o,$(notdir $(C_FILES)))
+
+TARGET = cbootimage
+CC = gcc
+CFLAGS=-Wall -O
+
+$(TARGET):$(OBJS)
+ $(CC) -o $(TARGET) $(OBJS) $(CFLAGS)
+
+clean:
+ rm -rf *.o $(TARGET)
diff --git a/system/cbootimage/aes_ref.c b/system/cbootimage/aes_ref.c
new file mode 100644
index 0000000..e86f237
--- /dev/null
+++ b/system/cbootimage/aes_ref.c
@@ -0,0 +1,330 @@
+/*
+ * (C) Copyright 2011
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* advanced encryption standard
+ * author: karl malbrain, malbrain@yahoo.com
+ */
+
+/*
+This work, including the source code, documentation
+and related data, is placed into the public domain.
+
+The orginal author is Karl Malbrain.
+
+THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY
+OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF
+MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE,
+ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE
+RESULTING FROM THE USE, MODIFICATION, OR
+REDISTRIBUTION OF THIS SOFTWARE.
+*/
+
+/*
+ * Modifications by NVIDIA:
+ * - Created nvaes_ref.h header.
+ * - Replaced type definitions with NVIDIA standard types.
+ * - Removed unneeded code that turns this source file into an executable.
+ * - Created function prototypes for some of the functions.
+ * - Reformatted the code to conform to coding conventions.
+ */
+
+#include "nvaes_ref.h"
+
+static void shift_rows(u_int8_t *state);
+static void mix_sub_columns(u_int8_t *state);
+static void add_round_key(u_int32_t *state, u_int32_t *key);
+
+static u_int8_t s_Sbox[256] =
+{ /* forward s-box */
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
+ 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
+ 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
+ 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
+ 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
+ 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
+ 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
+ 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
+ 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
+ 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
+ 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
+ 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
+};
+
+/* combined Xtimes2[Sbox[]] */
+static u_int8_t s_Xtime2Sbox[256] =
+{
+ 0xc6, 0xf8, 0xee, 0xf6, 0xff, 0xd6, 0xde, 0x91,
+ 0x60, 0x02, 0xce, 0x56, 0xe7, 0xb5, 0x4d, 0xec,
+ 0x8f, 0x1f, 0x89, 0xfa, 0xef, 0xb2, 0x8e, 0xfb,
+ 0x41, 0xb3, 0x5f, 0x45, 0x23, 0x53, 0xe4, 0x9b,
+ 0x75, 0xe1, 0x3d, 0x4c, 0x6c, 0x7e, 0xf5, 0x83,
+ 0x68, 0x51, 0xd1, 0xf9, 0xe2, 0xab, 0x62, 0x2a,
+ 0x08, 0x95, 0x46, 0x9d, 0x30, 0x37, 0x0a, 0x2f,
+ 0x0e, 0x24, 0x1b, 0xdf, 0xcd, 0x4e, 0x7f, 0xea,
+ 0x12, 0x1d, 0x58, 0x34, 0x36, 0xdc, 0xb4, 0x5b,
+ 0xa4, 0x76, 0xb7, 0x7d, 0x52, 0xdd, 0x5e, 0x13,
+ 0xa6, 0xb9, 0x00, 0xc1, 0x40, 0xe3, 0x79, 0xb6,
+ 0xd4, 0x8d, 0x67, 0x72, 0x94, 0x98, 0xb0, 0x85,
+ 0xbb, 0xc5, 0x4f, 0xed, 0x86, 0x9a, 0x66, 0x11,
+ 0x8a, 0xe9, 0x04, 0xfe, 0xa0, 0x78, 0x25, 0x4b,
+ 0xa2, 0x5d, 0x80, 0x05, 0x3f, 0x21, 0x70, 0xf1,
+ 0x63, 0x77, 0xaf, 0x42, 0x20, 0xe5, 0xfd, 0xbf,
+ 0x81, 0x18, 0x26, 0xc3, 0xbe, 0x35, 0x88, 0x2e,
+ 0x93, 0x55, 0xfc, 0x7a, 0xc8, 0xba, 0x32, 0xe6,
+ 0xc0, 0x19, 0x9e, 0xa3, 0x44, 0x54, 0x3b, 0x0b,
+ 0x8c, 0xc7, 0x6b, 0x28, 0xa7, 0xbc, 0x16, 0xad,
+ 0xdb, 0x64, 0x74, 0x14, 0x92, 0x0c, 0x48, 0xb8,
+ 0x9f, 0xbd, 0x43, 0xc4, 0x39, 0x31, 0xd3, 0xf2,
+ 0xd5, 0x8b, 0x6e, 0xda, 0x01, 0xb1, 0x9c, 0x49,
+ 0xd8, 0xac, 0xf3, 0xcf, 0xca, 0xf4, 0x47, 0x10,
+ 0x6f, 0xf0, 0x4a, 0x5c, 0x38, 0x57, 0x73, 0x97,
+ 0xcb, 0xa1, 0xe8, 0x3e, 0x96, 0x61, 0x0d, 0x0f,
+ 0xe0, 0x7c, 0x71, 0xcc, 0x90, 0x06, 0xf7, 0x1c,
+ 0xc2, 0x6a, 0xae, 0x69, 0x17, 0x99, 0x3a, 0x27,
+ 0xd9, 0xeb, 0x2b, 0x22, 0xd2, 0xa9, 0x07, 0x33,
+ 0x2d, 0x3c, 0x15, 0xc9, 0x87, 0xaa, 0x50, 0xa5,
+ 0x03, 0x59, 0x09, 0x1a, 0x65, 0xd7, 0x84, 0xd0,
+ 0x82, 0x29, 0x5a, 0x1e, 0x7b, 0xa8, 0x6d, 0x2c
+};
+
+/* combined Xtimes3[Sbox[]] */
+static u_int8_t s_Xtime3Sbox[256] =
+{
+ 0xa5, 0x84, 0x99, 0x8d, 0x0d, 0xbd, 0xb1, 0x54,
+ 0x50, 0x03, 0xa9, 0x7d, 0x19, 0x62, 0xe6, 0x9a,
+ 0x45, 0x9d, 0x40, 0x87, 0x15, 0xeb, 0xc9, 0x0b,
+ 0xec, 0x67, 0xfd, 0xea, 0xbf, 0xf7, 0x96, 0x5b,
+ 0xc2, 0x1c, 0xae, 0x6a, 0x5a, 0x41, 0x02, 0x4f,
+ 0x5c, 0xf4, 0x34, 0x08, 0x93, 0x73, 0x53, 0x3f,
+ 0x0c, 0x52, 0x65, 0x5e, 0x28, 0xa1, 0x0f, 0xb5,
+ 0x09, 0x36, 0x9b, 0x3d, 0x26, 0x69, 0xcd, 0x9f,
+ 0x1b, 0x9e, 0x74, 0x2e, 0x2d, 0xb2, 0xee, 0xfb,
+ 0xf6, 0x4d, 0x61, 0xce, 0x7b, 0x3e, 0x71, 0x97,
+ 0xf5, 0x68, 0x00, 0x2c, 0x60, 0x1f, 0xc8, 0xed,
+ 0xbe, 0x46, 0xd9, 0x4b, 0xde, 0xd4, 0xe8, 0x4a,
+ 0x6b, 0x2a, 0xe5, 0x16, 0xc5, 0xd7, 0x55, 0x94,
+ 0xcf, 0x10, 0x06, 0x81, 0xf0, 0x44, 0xba, 0xe3,
+ 0xf3, 0xfe, 0xc0, 0x8a, 0xad, 0xbc, 0x48, 0x04,
+ 0xdf, 0xc1, 0x75, 0x63, 0x30, 0x1a, 0x0e, 0x6d,
+ 0x4c, 0x14, 0x35, 0x2f, 0xe1, 0xa2, 0xcc, 0x39,
+ 0x57, 0xf2, 0x82, 0x47, 0xac, 0xe7, 0x2b, 0x95,
+ 0xa0, 0x98, 0xd1, 0x7f, 0x66, 0x7e, 0xab, 0x83,
+ 0xca, 0x29, 0xd3, 0x3c, 0x79, 0xe2, 0x1d, 0x76,
+ 0x3b, 0x56, 0x4e, 0x1e, 0xdb, 0x0a, 0x6c, 0xe4,
+ 0x5d, 0x6e, 0xef, 0xa6, 0xa8, 0xa4, 0x37, 0x8b,
+ 0x32, 0x43, 0x59, 0xb7, 0x8c, 0x64, 0xd2, 0xe0,
+ 0xb4, 0xfa, 0x07, 0x25, 0xaf, 0x8e, 0xe9, 0x18,
+ 0xd5, 0x88, 0x6f, 0x72, 0x24, 0xf1, 0xc7, 0x51,
+ 0x23, 0x7c, 0x9c, 0x21, 0xdd, 0xdc, 0x86, 0x85,
+ 0x90, 0x42, 0xc4, 0xaa, 0xd8, 0x05, 0x01, 0x12,
+ 0xa3, 0x5f, 0xf9, 0xd0, 0x91, 0x58, 0x27, 0xb9,
+ 0x38, 0x13, 0xb3, 0x33, 0xbb, 0x70, 0x89, 0xa7,
+ 0xb6, 0x22, 0x92, 0x20, 0x49, 0xff, 0x78, 0x7a,
+ 0x8f, 0xf8, 0x80, 0x17, 0xda, 0x31, 0xc6, 0xb8,
+ 0xc3, 0xb0, 0x77, 0x11, 0xcb, 0xfc, 0xd6, 0x3a
+};
+
+/* exchanges columns in each of 4 rows
+ * row0 - unchanged, row1- shifted left 1,
+ * row2 - shifted left 2 and row3 - shifted left 3
+ */
+static void
+shift_rows(u_int8_t *state)
+{
+ u_int8_t tmp;
+
+ /* just substitute row 0 */
+ state[ 0] = s_Sbox[state[ 0]];
+ state[ 4] = s_Sbox[state[ 4]];
+ state[ 8] = s_Sbox[state[ 8]];
+ state[12] = s_Sbox[state[12]];
+
+ /* rotate row 1 */
+ tmp = s_Sbox[state[ 1]];
+ state[ 1] = s_Sbox[state[ 5]];
+ state[ 5] = s_Sbox[state[ 9]];
+ state[ 9] = s_Sbox[state[13]];
+ state[13] = tmp;
+
+ /* rotate row 2 */
+ tmp = s_Sbox[state[ 2]];
+ state[ 2] = s_Sbox[state[10]];
+ state[10] = tmp;
+ tmp = s_Sbox[state[ 6]];
+ state[ 6] = s_Sbox[state[14]];
+ state[14] = tmp;
+
+ /* rotate row 3 */
+ tmp = s_Sbox[state[15]];
+ state[15] = s_Sbox[state[11]];
+ state[11] = s_Sbox[state[ 7]];
+ state[ 7] = s_Sbox[state[ 3]];
+ state[ 3] = tmp;
+}
+
+/* recombine and mix each row in a column */
+static void
+mix_sub_columns(u_int8_t *state)
+{
+ u_int8_t tmp[4 * NVAES_STATECOLS];
+
+ /* mixing column 0 */
+ tmp[ 0] = s_Xtime2Sbox[state[ 0]] ^ s_Xtime3Sbox[state[ 5]] ^
+ s_Sbox[state[10]] ^ s_Sbox[state[15]];
+ tmp[ 1] = s_Sbox[state[ 0]] ^ s_Xtime2Sbox[state[ 5]] ^
+ s_Xtime3Sbox[state[10]] ^ s_Sbox[state[15]];
+ tmp[ 2] = s_Sbox[state[ 0]] ^ s_Sbox[state[ 5]] ^
+ s_Xtime2Sbox[state[10]] ^ s_Xtime3Sbox[state[15]];
+ tmp[ 3] = s_Xtime3Sbox[state[ 0]] ^ s_Sbox[state[ 5]] ^
+ s_Sbox[state[10]] ^ s_Xtime2Sbox[state[15]];
+
+ /* mixing column 1 */
+ tmp[ 4] = s_Xtime2Sbox[state[ 4]] ^ s_Xtime3Sbox[state[ 9]] ^
+ s_Sbox[state[14]] ^ s_Sbox[state[ 3]];
+ tmp[ 5] = s_Sbox[state[ 4]] ^ s_Xtime2Sbox[state[ 9]] ^
+ s_Xtime3Sbox[state[14]] ^ s_Sbox[state[ 3]];
+ tmp[ 6] = s_Sbox[state[ 4]] ^ s_Sbox[state[ 9]] ^
+ s_Xtime2Sbox[state[14]] ^ s_Xtime3Sbox[state[ 3]];
+ tmp[ 7] = s_Xtime3Sbox[state[ 4]] ^ s_Sbox[state[ 9]] ^
+ s_Sbox[state[14]] ^ s_Xtime2Sbox[state[ 3]];
+
+ /* mixing column 2 */
+ tmp[ 8] = s_Xtime2Sbox[state[ 8]] ^ s_Xtime3Sbox[state[13]] ^
+ s_Sbox[state[ 2]] ^ s_Sbox[state[ 7]];
+ tmp[ 9] = s_Sbox[state[ 8]] ^ s_Xtime2Sbox[state[13]] ^
+ s_Xtime3Sbox[state[ 2]] ^ s_Sbox[state[ 7]];
+ tmp[10] = s_Sbox[state[ 8]] ^ s_Sbox[state[13]] ^
+ s_Xtime2Sbox[state[ 2]] ^ s_Xtime3Sbox[state[ 7]];
+ tmp[11] = s_Xtime3Sbox[state[ 8]] ^ s_Sbox[state[13]] ^
+ s_Sbox[state[ 2]] ^ s_Xtime2Sbox[state[ 7]];
+
+ /* mixing column 3 */
+ tmp[12] = s_Xtime2Sbox[state[12]] ^ s_Xtime3Sbox[state[ 1]] ^
+ s_Sbox[state[ 6]] ^ s_Sbox[state[11]];
+ tmp[13] = s_Sbox[state[12]] ^ s_Xtime2Sbox[state[ 1]] ^
+ s_Xtime3Sbox[state[ 6]] ^ s_Sbox[state[11]];
+ tmp[14] = s_Sbox[state[12]] ^ s_Sbox[state[ 1]] ^
+ s_Xtime2Sbox[state[ 6]] ^ s_Xtime3Sbox[state[11]];
+ tmp[15] = s_Xtime3Sbox[state[12]] ^ s_Sbox[state[ 1]] ^
+ s_Sbox[state[ 6]] ^ s_Xtime2Sbox[state[11]];
+
+ memcpy (state, tmp, sizeof(tmp));
+}
+
+/* encrypt/decrypt columns of the key
+ * n.b. you can replace this with
+ * byte-wise xor if you wish.
+ */
+
+static void
+add_round_key(u_int32_t *state, u_int32_t *key)
+{
+ int idx;
+
+ for (idx = 0; idx < 4; idx++)
+ state[idx] ^= key[idx];
+}
+
+static u_int8_t s_Rcon[11] =
+{
+ 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36
+};
+
+/* produce NVAES_STATECOLS bytes for each round */
+void
+nv_aes_expand_key(u_int8_t *key, u_int8_t *expkey)
+{
+ u_int8_t tmp0, tmp1, tmp2, tmp3, tmp4;
+ u_int32_t idx;
+
+ memcpy(expkey, key, NVAES_KEYCOLS * 4);
+
+ for (idx = NVAES_KEYCOLS;
+ idx < NVAES_STATECOLS * (NVAES_ROUNDS + 1);
+ idx++) {
+ tmp0 = expkey[4*idx - 4];
+ tmp1 = expkey[4*idx - 3];
+ tmp2 = expkey[4*idx - 2];
+ tmp3 = expkey[4*idx - 1];
+ if (!(idx % NVAES_KEYCOLS)) {
+ tmp4 = tmp3;
+ tmp3 = s_Sbox[tmp0];
+ tmp0 = s_Sbox[tmp1] ^ s_Rcon[idx/NVAES_KEYCOLS];
+ tmp1 = s_Sbox[tmp2];
+ tmp2 = s_Sbox[tmp4];
+ } else if (NVAES_KEYCOLS > 6 && idx % NVAES_KEYCOLS == 4 ) {
+ tmp0 = s_Sbox[tmp0];
+ tmp1 = s_Sbox[tmp1];
+ tmp2 = s_Sbox[tmp2];
+ tmp3 = s_Sbox[tmp3];
+ }
+
+ expkey[4*idx+0] = expkey[4*idx - 4*NVAES_KEYCOLS + 0] ^ tmp0;
+ expkey[4*idx+1] = expkey[4*idx - 4*NVAES_KEYCOLS + 1] ^ tmp1;
+ expkey[4*idx+2] = expkey[4*idx - 4*NVAES_KEYCOLS + 2] ^ tmp2;
+ expkey[4*idx+3] = expkey[4*idx - 4*NVAES_KEYCOLS + 3] ^ tmp3;
+ }
+}
+
+/* encrypt one 128 bit block */
+void
+nv_aes_encrypt(u_int8_t *in, u_int8_t *expkey, u_int8_t *out)
+{
+ u_int8_t state[NVAES_STATECOLS * 4];
+ u_int32_t round;
+
+ memcpy(state, in, NVAES_STATECOLS * 4);
+ add_round_key((u_int32_t *)state, (u_int32_t *)expkey);
+
+ for (round = 1; round < NVAES_ROUNDS + 1; round++) {
+ if (round < NVAES_ROUNDS)
+ mix_sub_columns (state);
+ else
+ shift_rows (state);
+
+ add_round_key((u_int32_t *)state, (u_int32_t *)expkey +
+ round * NVAES_STATECOLS);
+ }
+
+ memcpy(out, state, sizeof(state));
+}
diff --git a/system/cbootimage/cbootimage.c b/system/cbootimage/cbootimage.c
new file mode 100644
index 0000000..798ce04
--- /dev/null
+++ b/system/cbootimage/cbootimage.c
@@ -0,0 +1,258 @@
+/**
+ * Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * cbootimage.c - Implementation of the cbootimage tool.
+ */
+
+#include "cbootimage.h"
+#include "nvbctlib.h"
+#include "crypto.h"
+#include "data_layout.h"
+#include "parse.h"
+#include "set.h"
+
+/*
+ * Global data
+ */
+int enable_debug = 0;
+
+static int help_only = 0; // Only print help & exit
+
+/*
+ * Function prototypes
+ */
+int main(int argc, char *argv[]);
+
+static int
+query_alloc(build_image_context *context,
+ nvbct_lib_id size_id,
+ u_int8_t **dst)
+{
+ u_int32_t size;
+
+ /* Note: 3rd argument not used in this particular query. */
+ if (context->bctlib.get_value(size_id,
+ &size, context->bct) != 0)
+ return -ENODATA;
+ *dst = malloc(size);
+
+ if (*dst == NULL)
+ return -ENOMEM;
+
+ memset(*dst, 0, size);
+
+ return 0;
+}
+
+static void
+cleanup_context(build_image_context *context)
+{
+ destroy_block_list(context->memory);
+ destroy_addon_list(context->addon_tbl.addon_item_list);
+ free(context->bct);
+}
+
+static int
+init_context(build_image_context *context)
+{
+ int e = 0;
+
+ /* Set defaults */
+ context->memory = new_block_list();
+ context->journal_blk = 1; /* Default to 1st block */
+
+ /* Allocate space for the bct.
+ * Note that this is different from the old code which pointed directly
+ * into a memory image.
+ */
+ e = query_alloc(context, nvbct_lib_id_bct_size, &(context->bct));
+ if (e != 0)
+ goto fail;
+
+ context_set_value(context, token_page_size, 2048);
+ context_set_value(context, token_redundancy, 1);
+ context_set_value(context, token_version, 1);
+
+ return 0;
+
+ fail:
+ cleanup_context(context);
+
+ return e;
+}
+
+int
+write_image_file(build_image_context *context)
+{
+ assert(context != NULL);
+
+ return write_block_raw(context);
+}
+
+static void
+usage(void)
+{
+ printf("Usage: cbootimage [options] configfile imagename\n");
+ printf(" options:\n");
+ printf(" -h, --help, -? Display this message.\n");
+ printf(" -d, --debug Output debugging information.\n");
+ printf(" configfile File with configuration information\n");
+ printf(" imagename Output image name\n");
+}
+
+static int
+process_command_line(int argc, char *argv[], build_image_context *context)
+{
+ int arg = 1;
+
+ while (arg < argc) {
+ /* Process the next argument. */
+ if (!strcmp(argv[arg], "-h") ||
+ !strcmp(argv[arg], "--help") ||
+ !strcmp(argv[arg], "-?")) {
+ help_only = 1;
+ usage();
+ return 0;
+ } else if (!strcmp(argv[arg], "-d") ||
+ !strcmp(argv[arg], "--debug")) {
+ enable_debug = 1;
+ arg++;
+ } else if (argv[arg][0] == '-') {
+ printf("Illegal option %s\n", argv[arg]);
+ usage();
+ return -EINVAL;
+ }
+ else
+ break; /* Finished with options */
+ }
+
+ /* Handle file specification errors. */
+ switch (argc - arg) {
+ case 0:
+ printf("Missing configuration and image file names.\n");
+ usage();
+ return -EINVAL;
+
+ case 1:
+ printf("Missing configuration or image file name.\n");
+ usage();
+ return -EINVAL;
+
+ case 2:
+ /* Correct args, so break from the switch statement. */
+ break;
+
+ default:
+ printf("Too many arguments.\n");
+ usage();
+ return -EINVAL;
+ }
+
+ /* Open the configuration file. */
+ context->config_file = fopen(argv[arg], "r");
+ if (context->config_file == NULL) {
+ printf("Error opening config file.\n");
+ return -ENODATA;
+ }
+
+ /* Record the output filename */
+ context->image_filename = argv[arg + 1];
+
+ /* Set up the Nvbctlib function pointers. */
+ nvbct_lib_get_fns(&(context->bctlib));
+
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int e = 0;
+ build_image_context context;
+ u_int32_t data = 0;
+
+ memset(&context, 0, sizeof(build_image_context));
+
+ /* Process command line arguments. */
+ if (process_command_line(argc, argv, &context) != 0)
+ return -EINVAL;
+
+ if (help_only)
+ return 1;
+
+ e = init_context(&context);
+ if (e != 0) {
+ printf("context initialization failed. Aborting.\n");
+ return e;
+ }
+
+ if (enable_debug) {
+ /* Debugging information... */
+ e = context.bctlib.get_value(nvbct_lib_id_bct_size,
+ &data, context.bct);
+ printf("bct size: %d\n", e == 0 ? data : -1);
+ }
+
+ /* Open the raw output file. */
+ context.raw_file = fopen(context.image_filename,
+ "w+");
+ if (context.raw_file == NULL) {
+ printf("Error opening raw file %s.\n",
+ context.image_filename);
+ goto fail;
+ }
+
+ /* Parse & process the contents of the config file. */
+ process_config_file(&context);
+
+ /* Update the bct file */
+ /* Update the add on file */
+ e = update_addon_item(&context);
+ if ( e!= 0) {
+ printf("Write addon item failed, error: %d.\n", e);
+ goto fail;
+ }
+ /* Peform final signing & encryption of bct. */
+ e = sign_bct(&context, context.bct);
+ if (e != 0) {
+ printf("Signing BCT failed, error: %d.\n", e);
+ goto fail;
+ }
+ /* Write the image file. */
+ /* The image hasn't been written yet. */
+ if (write_image_file(&context) != 0)
+ printf("Error writing image file.\n");
+ else
+ printf("Image file %s has been successfully generated!\n",
+ context.image_filename);
+
+ fail:
+ /* Close the file(s). */
+ if (context.raw_file)
+ fclose(context.raw_file);
+
+ /* Clean up memory. */
+ cleanup_context(&context);
+
+ return e;
+}
diff --git a/system/cbootimage/cbootimage.h b/system/cbootimage/cbootimage.h
new file mode 100644
index 0000000..41c9baf
--- /dev/null
+++ b/system/cbootimage/cbootimage.h
@@ -0,0 +1,141 @@
+/**
+ * Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * cbootimage.h - Definitions for the cbootimage code.
+ */
+
+#ifndef INCLUDED_BUILDIMAGE_H
+#define INCLUDED_BUILDIMAGE_H
+
+#include "nvboot_bct.h"
+#include "nvbctlib.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+
+#define NVBOOT_AES_BLOCK_SIZE_LOG2 4
+
+#define KEY_LENGTH (128/8)
+
+#define MAX_BUFFER 200
+#define MAX_STR_LEN 20
+#define MAX_BOOTLOADER_SIZE (16 * 1024 * 1024)
+
+/*
+ * Enumerations
+ */
+
+typedef enum
+{
+ file_type_bl = 0,
+ file_type_bct,
+ file_type_addon
+} file_type;
+/*
+ * Structures
+ */
+typedef struct item_rec
+{
+ u_int8_t unique_name[4];
+ u_int32_t Location;
+ u_int32_t size;
+ u_int32_t attribute;
+ u_int32_t reserve[4];
+ u_int32_t item_checksum[4];
+}item;
+
+typedef struct addon_item_rec
+{
+ struct item_rec item;
+ char addon_filename[MAX_BUFFER];
+ int item_index;
+ struct addon_item_rec *next;
+}addon_item;
+
+typedef struct table_rec
+{
+ u_int8_t magic_id[8];
+ u_int32_t table_checksum[4];
+ u_int32_t table_size;
+
+}table;
+
+typedef struct addon_table_rec
+{
+ struct table_rec table;
+ u_int8_t addon_item_no;
+ struct addon_item_rec *addon_item_list;
+}addon_table;
+
+typedef struct build_image_context_rec
+{
+ FILE *config_file;
+ char *image_filename;
+ FILE *raw_file;
+ nvbct_lib_fns bctlib;
+ u_int32_t block_size;
+ u_int32_t block_size_log2;
+ u_int32_t page_size;
+ u_int32_t page_size_log2;
+ u_int32_t pages_per_blk;
+ u_int32_t partition_size;
+ u_int32_t redundancy;
+ u_int32_t version;
+ /* Allocation data. */
+ struct blk_data_rec *memory; /* Representation of memory */
+ /* block number for the (first) journal block */
+ u_int32_t journal_blk;
+
+ char *newbl_filename;
+ u_int32_t newbl_load_addr;
+ u_int32_t newbl_entry_point;
+ u_int32_t newbl_attr;
+ u_int8_t *bct;
+
+ struct addon_table_rec addon_tbl;
+ char *bct_filename;
+ u_int32_t last_bl_blk;
+ u_int32_t addon_tbl_blk;
+} build_image_context;
+
+/* Function prototypes */
+
+int write_image_file(build_image_context *context);
+
+/* Global data */
+extern int enable_debug;
+
+/* Useful macros */
+
+#define GET_VALUE(id, ptr) \
+ (void)context->bctlib.get_value(nvbct_lib_id_##id, \
+ ptr, \
+ context->bct);
+
+#define SET_VALUE(id, value) \
+ (void)context->bctlib.set_value(nvbct_lib_id_##id, \
+ value, \
+ context->bct);
+
+#endif /* #ifndef INCLUDED_BUILDIMAGE_H */
diff --git a/system/cbootimage/crypto.c b/system/cbootimage/crypto.c
new file mode 100644
index 0000000..e5ade76
--- /dev/null
+++ b/system/cbootimage/crypto.c
@@ -0,0 +1,303 @@
+/*
+ * (C) Copyright 2011
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * crypto.c - Cryptography support
+ */
+#include "crypto.h"
+#include "nvaes_ref.h"
+#include <stdio.h>
+
+/* Local function declarations */
+static void
+apply_cbc_chain_data(u_int8_t *cbc_chain_data,
+ u_int8_t *src,
+ u_int8_t *dst);
+
+static void
+generate_key_schedule(u_int8_t *key, u_int8_t *key_schedule);
+
+static void
+encrypt_object( u_int8_t *key_schedule,
+ u_int8_t *src,
+ u_int8_t *dst,
+ u_int32_t num_aes_blocks);
+
+static int
+encrypt_and_sign(u_int8_t *key,
+ u_int8_t *src,
+ u_int32_t length,
+ u_int8_t *sig_dst);
+
+u_int8_t enable_debug_crypto = 0;
+
+/* Implementation */
+static u_int8_t zero_key[16] = { 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 };
+
+static void
+print_vector(char *name, u_int32_t num_bytes, u_int8_t *data)
+{
+ u_int32_t i;
+
+ printf("%s [%d] @0x%08x", name, num_bytes, (u_int32_t)data);
+ for (i=0; i<num_bytes; i++) {
+ if ( i % 16 == 0 )
+ printf(" = ");
+ printf("%02x", data[i]);
+ if ( (i+1) % 16 != 0 )
+ printf(" ");
+ }
+ printf("\n");
+}
+
+
+static void
+apply_cbc_chain_data(u_int8_t *cbc_chain_data,
+ u_int8_t *src,
+ u_int8_t *dst)
+{
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ *dst++ = *src++ ^ *cbc_chain_data++;
+ }
+}
+
+static void
+generate_key_schedule(u_int8_t *key, u_int8_t *key_schedule)
+{
+ /*
+ * The only need for a key is for signing/checksum purposes, so
+ * expand a key of 0's.
+ */
+ nv_aes_expand_key(zero_key, key_schedule);
+}
+
+static void
+encrypt_object(u_int8_t *key_schedule,
+ u_int8_t *src,
+ u_int8_t *dst,
+ u_int32_t num_aes_blocks)
+{
+ u_int32_t i;
+ u_int8_t *cbc_chain_data;
+ u_int8_t tmp_data[KEY_LENGTH];
+
+ cbc_chain_data = zero_key; /* Convenient array of 0's for IV */
+
+ for (i = 0; i < num_aes_blocks; i++) {
+ if (enable_debug_crypto) {
+ printf("encrypt_object: block %d of %d\n", i,
+ num_aes_blocks);
+ print_vector("AES Src", KEY_LENGTH, src);
+ }
+
+ /* Apply the chain data */
+ apply_cbc_chain_data(cbc_chain_data, src, tmp_data);
+
+ if (enable_debug_crypto)
+ print_vector("AES Xor", KEY_LENGTH,
+ tmp_data);
+
+ /* encrypt the AES block */
+ nv_aes_encrypt(tmp_data, key_schedule, dst);
+
+ if (enable_debug_crypto)
+ print_vector("AES Dst", KEY_LENGTH, dst);
+ /* Update pointers for next loop. */
+ cbc_chain_data = dst;
+ src += KEY_LENGTH;
+ dst += KEY_LENGTH;
+ }
+}
+
+static void
+left_shift_vector(u_int8_t *in,
+ u_int8_t *out,
+ u_int32_t size)
+{
+ u_int32_t i;
+ u_int8_t carry = 0;
+
+ for (i=0; i<size; i++) {
+ u_int32_t j = size-1-i;
+
+ out[j] = (in[j] << 1) | carry;
+ carry = in[j] >> 7; /* get most significant bit */
+ }
+}
+
+static void
+sign_objext(
+ u_int8_t *key,
+ u_int8_t *key_schedule,
+ u_int8_t *src,
+ u_int8_t *dst,
+ u_int32_t num_aes_blocks)
+{
+ u_int32_t i;
+ u_int8_t *cbc_chain_data;
+
+ u_int8_t l[KEY_LENGTH];
+ u_int8_t k1[KEY_LENGTH];
+ u_int8_t tmp_data[KEY_LENGTH];
+
+ cbc_chain_data = zero_key; /* Convenient array of 0's for IV */
+
+ /* compute k1 constant needed by AES-CMAC calculation */
+
+ for (i=0; i<KEY_LENGTH; i++)
+ tmp_data[i] = 0;
+
+ encrypt_object(key_schedule, tmp_data, l, 1);
+
+ if (enable_debug_crypto)
+ print_vector("AES(key, nonce)", KEY_LENGTH, l);
+
+ left_shift_vector(l, k1, sizeof(l));
+
+ if (enable_debug_crypto)
+ print_vector("L", KEY_LENGTH, l);
+
+ if ( (l[0] >> 7) != 0 ) /* get MSB of L */
+ k1[KEY_LENGTH-1] ^= AES_CMAC_CONST_RB;
+
+ if (enable_debug_crypto)
+ print_vector("K1", KEY_LENGTH, k1);
+
+ /* compute the AES-CMAC value */
+ for (i = 0; i < num_aes_blocks; i++) {
+ /* Apply the chain data */
+ apply_cbc_chain_data(cbc_chain_data, src, tmp_data);
+
+ /* for the final block, XOR k1 into the IV */
+ if ( i == num_aes_blocks-1 )
+ apply_cbc_chain_data(tmp_data, k1, tmp_data);
+
+ /* encrypt the AES block */
+ nv_aes_encrypt(tmp_data, key_schedule, (u_int8_t*)dst);
+
+ if (enable_debug_crypto) {
+ printf("sign_objext: block %d of %d\n", i,
+ num_aes_blocks);
+ print_vector("AES-CMAC Src", KEY_LENGTH, src);
+ print_vector("AES-CMAC Xor", KEY_LENGTH, tmp_data);
+ print_vector("AES-CMAC Dst",
+ KEY_LENGTH,
+ (u_int8_t*)dst);
+ }
+
+ /* Update pointers for next loop. */
+ cbc_chain_data = (u_int8_t*)dst;
+ src += KEY_LENGTH;
+ }
+
+ if (enable_debug_crypto)
+ print_vector("AES-CMAC Hash", KEY_LENGTH, (u_int8_t*)dst);
+}
+
+static int
+encrypt_and_sign(u_int8_t *key,
+ u_int8_t *src,
+ u_int32_t length,
+ u_int8_t *sig_dst)
+{
+ u_int32_t num_aes_blocks;
+ u_int8_t key_schedule[4*NVAES_STATECOLS*(NVAES_ROUNDS+1)];
+
+ if (enable_debug_crypto) {
+ printf("encrypt_and_sign: length = %d\n", length);
+ print_vector("AES key", KEY_LENGTH, key);
+ }
+
+ generate_key_schedule(key, key_schedule);
+
+ num_aes_blocks = ICEIL(length, KEY_LENGTH);
+
+ if (enable_debug_crypto)
+ printf("encrypt_and_sign: begin signing\n");
+
+ /* encrypt the data, overwriting the result in signature. */
+ sign_objext(key, key_schedule, src, sig_dst, num_aes_blocks);
+
+ if (enable_debug_crypto)
+ printf("encrypt_and_sign: end signing\n");
+
+ return 0;
+}
+
+int
+sign_data_block(u_int8_t *source,
+ u_int32_t length,
+ u_int8_t *signature)
+{
+ return encrypt_and_sign(zero_key,
+ source,
+ length,
+ signature);
+}
+
+int
+sign_bct(build_image_context *context,
+ u_int8_t *bct)
+{
+ u_int32_t Offset;
+ u_int32_t length;
+ u_int32_t hash_size;
+ u_int8_t *hash_buffer = NULL;
+ int e = 0;
+
+ assert(bct != NULL);
+
+ if (context->bctlib.get_value(nvbct_lib_id_hash_size,
+ &hash_size,
+ bct) != 0)
+ return -ENODATA;
+ if (context->bctlib.get_value(nvbct_lib_id_crypto_offset,
+ &Offset,
+ bct) != 0)
+ return -ENODATA;
+ if (context->bctlib.get_value(nvbct_lib_id_crypto_length,
+ &length,
+ bct) != 0)
+ return -ENODATA;
+
+ hash_buffer = malloc(hash_size);
+ if (hash_buffer == NULL)
+ return -ENOMEM;
+ e = sign_data_block(bct + Offset, length, hash_buffer);
+ if (e != 0)
+ goto fail;
+ e = context->bctlib.set_data(nvbct_lib_id_crypto_hash,
+ hash_buffer,
+ hash_size,
+ bct);
+ if (e != 0)
+ goto fail;
+
+ fail:
+ free(hash_buffer);
+ return e;
+}
+
diff --git a/system/cbootimage/crypto.h b/system/cbootimage/crypto.h
new file mode 100644
index 0000000..27c4dd6
--- /dev/null
+++ b/system/cbootimage/crypto.h
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * crypto.h - Definitions for the crypto support.
+ */
+
+#ifndef INCLUDED_CRYPTO_H_N
+#define INCLUDED_CRYPTO_H_N
+
+#include "cbootimage.h"
+
+/* lengths, in bytes */
+#define KEY_LENGTH (128/8)
+
+#define ICEIL(a, b) (((a) + (b) - 1)/(b))
+
+#define AES_CMAC_CONST_RB 0x87 // from RFC 4493, Figure 2.2
+
+/* Function prototypes */
+
+int
+sign_bct(build_image_context *context,
+ u_int8_t *bct);
+
+int
+sign_data_block(u_int8_t *source,
+ u_int32_t length,
+ u_int8_t *signature);
+
+#endif /* #ifndef INCLUDED_CRYPTO_H */
diff --git a/system/cbootimage/data_layout.c b/system/cbootimage/data_layout.c
new file mode 100644
index 0000000..3c49f9f
--- /dev/null
+++ b/system/cbootimage/data_layout.c
@@ -0,0 +1,1027 @@
+/**
+ * Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * data_layout.c - Code to manage the layout of data in the boot device.
+ *
+ */
+
+#include "data_layout.h"
+#include "cbootimage.h"
+#include "crypto.h"
+#include "set.h"
+#include <sys/param.h>
+
+typedef struct blk_data_rec
+{
+ u_int32_t blk_number;
+ u_int32_t pages_used; /* pages always used starting from 0. */
+ u_int8_t *data;
+
+ /* Pointer to ECC errors? */
+
+ struct blk_data_rec *next;
+} block_data;
+
+/* Function prototypes */
+static block_data
+*new_block(u_int32_t blk_number, u_int32_t block_size);
+static block_data
+*find_block(u_int32_t blk_number, block_data *block_list);
+static block_data
+*add_block(u_int32_t blk_number, block_data **block_list,
+ u_int32_t block_size);
+static int
+erase_block(build_image_context *context, u_int32_t blk_number);
+
+static int
+write_page(build_image_context *context,
+ u_int32_t blk_number,
+ u_int32_t page_number,
+ u_int8_t *data);
+
+static void
+insert_padding(u_int8_t *data, u_int32_t length);
+
+static void
+write_padding(u_int8_t *data, u_int32_t length);
+
+static int write_bct(build_image_context *context,
+ u_int32_t block,
+ u_int32_t bct_slot);
+
+static void
+set_bl_data(build_image_context *context,
+ u_int32_t instance,
+ u_int32_t start_blk,
+ u_int32_t start_page,
+ u_int32_t length);
+
+static int write_bootloaders(build_image_context *context);
+
+static void find_new_journal_blk(build_image_context *context);
+static int begin_update (build_image_context *context);
+static int finish_update(build_image_context *context);
+static u_int32_t
+iceil_log2(u_int32_t a, u_int32_t b)
+{
+ return (a + (1 << b) - 1) >> b;
+}
+
+static block_data *new_block(u_int32_t blk_number, u_int32_t block_size)
+{
+ block_data *new_block = malloc(sizeof(block_data));
+ if (new_block == NULL)
+ return NULL;
+
+ new_block->blk_number = blk_number;
+ new_block->pages_used = 0;
+ new_block->data = malloc(block_size);
+ if (new_block->data == NULL) {
+ free(new_block);
+ return NULL;
+ }
+ new_block->next = NULL;
+
+ memset(new_block->data, 0, block_size);
+
+ return new_block;
+}
+
+block_data *new_block_list(void)
+{
+ return NULL;
+}
+
+void destroy_block_list(block_data *block_list)
+{
+ block_data *next;
+
+ while (block_list) {
+ next = block_list->next;
+ free(block_list->data);
+ free(block_list);
+ block_list = next;
+ }
+}
+
+static block_data *find_block(u_int32_t blk_number, block_data *block_list)
+{
+ while (block_list) {
+ if (block_list->blk_number == blk_number)
+ return block_list;
+
+ block_list = block_list->next;
+ }
+
+ return NULL;
+}
+
+/* Returns pointer to block after adding it to block_list, if needed. */
+static block_data *add_block(u_int32_t blk_number,
+ block_data **block_list,
+ u_int32_t block_size)
+{
+ block_data *block = find_block(blk_number,*block_list);
+ block_data *parent;
+
+ if (block == NULL) {
+ block = new_block(blk_number, block_size);
+ if (block == NULL)
+ return block;
+
+ /* Insert block into the list */
+ if ((*block_list == NULL) ||
+ (blk_number < (*block_list)->blk_number)) {
+ block->next = *block_list;
+ *block_list = block;
+ } else {
+ /* Search for the correct place to insert the block. */
+ parent = *block_list;
+ while (parent->next != NULL &&
+ parent->next->blk_number < blk_number) {
+ parent = parent->next;
+ }
+
+ block->next = parent->next;
+ parent->next = block;
+ }
+ }
+
+ return block;
+}
+
+static int
+erase_block(build_image_context *context, u_int32_t blk_number)
+{
+ block_data *block;
+
+ assert(context != NULL);
+
+ block = add_block(blk_number, &(context->memory), context->block_size);
+
+ if (block == NULL)
+ return -ENOMEM;
+ if (block->data == NULL)
+ return -ENOMEM;
+
+ memset(block->data, 0, context->block_size);
+ block->pages_used = 0;
+ return 0;
+}
+
+static int
+write_page(build_image_context *context,
+ u_int32_t blk_number,
+ u_int32_t page_number,
+ u_int8_t *data)
+{
+ block_data *block;
+ u_int8_t *page_ptr;
+
+ assert(context);
+
+ block = add_block(blk_number, &(context->memory), context->block_size);
+
+ if (block == NULL)
+ return -ENOMEM;
+ if (block->data == NULL)
+ return -ENOMEM;
+ assert(((page_number + 1) * context->page_size)
+ <= context->block_size);
+
+ if (block->pages_used != page_number) {
+ printf("Warning: Writing page in block out of order.\n");
+ printf(" block=%d page=%d\n", blk_number, page_number);
+ }
+
+ page_ptr = block->data + (page_number * context->page_size);
+ memcpy(page_ptr, data, context->page_size);
+ if (block->pages_used < (page_number+1))
+ block->pages_used = page_number+1;
+ return 0;
+}
+
+static void
+insert_padding(u_int8_t *data, u_int32_t length)
+{
+ u_int32_t aes_blks;
+ u_int32_t remaining;
+
+ aes_blks = iceil_log2(length, NVBOOT_AES_BLOCK_SIZE_LOG2);
+ remaining = (aes_blks << NVBOOT_AES_BLOCK_SIZE_LOG2) - length;
+
+ write_padding(data + length, remaining);
+}
+
+static void
+write_padding(u_int8_t *p, u_int32_t remaining)
+{
+ u_int8_t value = 0x80;
+
+ while (remaining) {
+ *p++ = value;
+ remaining--;
+ value = 0x00;
+ }
+}
+
+static int
+write_bct(build_image_context *context,
+ u_int32_t block,
+ u_int32_t bct_slot)
+{
+ u_int32_t bct_size;
+ u_int32_t pagesremaining;
+ u_int32_t page;
+ u_int32_t pages_per_bct;
+ u_int8_t *buffer;
+ u_int8_t *data;
+ int e = 0;
+
+ assert(context);
+
+ /* Note: 3rd argument not used in this particular query. */
+ (void)context->bctlib.get_value(nvbct_lib_id_bct_size,
+ &bct_size, context->bct);
+
+ pages_per_bct = iceil_log2(bct_size, context->page_size_log2);
+ pagesremaining = pages_per_bct;
+ page = bct_slot * pages_per_bct;
+
+ /* Create a local copy of the BCT data */
+ buffer = malloc(pages_per_bct * context->page_size);
+ if (buffer == NULL)
+ return -ENOMEM;
+ memset(buffer, 0, pages_per_bct * context->page_size);
+
+ memcpy(buffer, context->bct, bct_size);
+
+ insert_padding(buffer, bct_size);
+
+ /* Encrypt and compute hash */
+ e = sign_bct(context, buffer);
+ if (e != 0)
+ goto fail;
+
+ /* Write the BCT data to the storage device, picking up ECC errors */
+ data = buffer;
+ while (pagesremaining > 0) {
+ e = write_page(context, block, page, data);
+ if (e != 0)
+ goto fail;
+ page++;
+ pagesremaining--;
+ data += context->page_size;
+ }
+fail:
+ /* Cleanup */
+ free(buffer);
+ return e;
+}
+
+#define SET_BL_FIELD(instance, field, value) \
+do { \
+ (void)context->bctlib.setbl_param(instance, \
+ nvbct_lib_id_bl_##field, \
+ &(value), \
+ context->bct); \
+} while (0);
+
+#define GET_BL_FIELD(instance, field, ptr) \
+(void)context->bctlib.getbl_param(instance, \
+ nvbct_lib_id_bl_##field, \
+ ptr, \
+ context->bct);
+
+#define COPY_BL_FIELD(from, to, field) \
+do { \
+ u_int32_t v; \
+ GET_BL_FIELD(from, field, &v); \
+ SET_BL_FIELD(to, field, v); \
+} while (0);
+
+static void
+set_bl_data(build_image_context *context,
+ u_int32_t instance,
+ u_int32_t start_blk,
+ u_int32_t start_page,
+ u_int32_t length)
+{
+ assert(context);
+
+ SET_BL_FIELD(instance, version, context->version);
+ SET_BL_FIELD(instance, start_blk, start_blk);
+ SET_BL_FIELD(instance, start_page, start_page);
+ SET_BL_FIELD(instance, length, length);
+ SET_BL_FIELD(instance, load_addr, context->newbl_load_addr);
+ SET_BL_FIELD(instance, entry_point, context->newbl_entry_point);
+ SET_BL_FIELD(instance, attribute, context->newbl_attr);
+}
+
+
+/*
+ * In the interest of expediency, all BL's allocated from bottom to top start
+ * at page 0 of a block, and all BL's allocated from top to bottom end at
+ * the end of a block.
+ */
+/* TODO: Check for partition overflow */
+/* TODO: Refactor this code! */
+static int
+write_bootloaders(build_image_context *context)
+{
+ u_int32_t i;
+ u_int32_t j;
+ u_int32_t bl_instance;
+ u_int32_t bl_move_count = 0;
+ u_int32_t bl_move_remaining;
+ u_int32_t current_blk;
+ u_int32_t current_page;
+ u_int32_t pages_in_bl;
+ u_int8_t *bl_storage; /* Holds the Bl after reading */
+ u_int8_t *buffer; /* Holds the Bl for writing */
+ u_int8_t *src; /* Scans through the Bl during writing */
+ u_int32_t bl_length; /* In bytes */
+ u_int32_t bl_actual_size; /* In bytes */
+ u_int32_t pagesremaining;
+ u_int32_t virtual_blk;
+ u_int32_t pages_per_blk;
+ u_int32_t min_offset;
+ u_int32_t max_offset;
+ u_int32_t bl_0_version;
+ u_int32_t bl_used;
+ u_int8_t *hash_buffer;
+ u_int32_t hash_size;
+ u_int32_t bootloaders_max;
+ file_type bl_filetype = file_type_bl;
+ int e = 0;
+
+ assert(context);
+
+ pages_per_blk = 1 << (context->block_size_log2
+ - context->page_size_log2);
+
+ GET_VALUE(hash_size, &hash_size);
+ GET_VALUE(bootloaders_max, &bootloaders_max);
+
+ hash_buffer = malloc(hash_size);
+ if (hash_buffer == NULL)
+ return -ENOMEM;
+
+ if (enable_debug) {
+ printf("write_bootloaders()\n");
+ printf(" redundancy = %d\n", context->redundancy);
+ }
+
+ /* Make room for the Bl(s) in the BCT. */
+
+ /* Determine how many to move.
+ * Note that this code will count Bl[0] only if there is already
+ * a BL in the device.
+ */
+ GET_BL_FIELD(0, version, &bl_0_version);
+ GET_VALUE(bootloader_used, &bl_used);
+ for (bl_instance = 0; bl_instance < bl_used; bl_instance++) {
+ u_int32_t bl_version;
+ GET_BL_FIELD(bl_instance, version, &bl_version);
+ if (bl_version == bl_0_version)
+ bl_move_count++;
+ }
+
+ /* Adjust the move count, if needed, to avoid overflowing the BL table.
+ * This can happen due to too much redundancy.
+ */
+ bl_move_count = MIN(bl_move_count,
+ bootloaders_max - context->redundancy);
+
+ /* Move the Bl entries down. */
+ bl_move_remaining = bl_move_count;
+ while (bl_move_remaining > 0) {
+ u_int32_t inst_from = bl_move_remaining - 1;
+ u_int32_t inst_to =
+ bl_move_remaining + context->redundancy - 1;
+
+ COPY_BL_FIELD(inst_from, inst_to, version);
+ COPY_BL_FIELD(inst_from, inst_to, start_blk);
+ COPY_BL_FIELD(inst_from, inst_to, start_page);
+ COPY_BL_FIELD(inst_from, inst_to, length);
+ COPY_BL_FIELD(inst_from, inst_to, load_addr);
+ COPY_BL_FIELD(inst_from, inst_to, entry_point);
+ COPY_BL_FIELD(inst_from, inst_to, attribute);
+
+ (void)context->bctlib.getbl_param(inst_from,
+ nvbct_lib_id_bl_crypto_hash,
+ (u_int32_t*)hash_buffer,
+ context->bct);
+ (void)context->bctlib.setbl_param(inst_to,
+ nvbct_lib_id_bl_crypto_hash,
+ (u_int32_t*)hash_buffer,
+ context->bct);
+ bl_move_remaining--;
+ }
+
+ /* Read the BL into memory. */
+ if (read_from_image(context->newbl_filename,
+ context->page_size,
+ &bl_storage,
+ &bl_length,
+ &bl_actual_size,
+ bl_filetype) == 1) {
+ printf("Error reading Bootloader %s.\n",
+ context->newbl_filename);
+ exit(1);
+ }
+
+ pages_in_bl = iceil_log2(bl_length, context->page_size_log2);
+
+ current_blk = context->journal_blk+1;
+ current_page = 0;
+ for (bl_instance = 0; bl_instance < context->redundancy;
+ bl_instance++) {
+
+ pagesremaining = pages_in_bl;
+ /* Advance to the next block if needed. */
+ if (current_page > 0) {
+ current_blk++;
+ current_page = 0;
+ }
+
+ virtual_blk = 0;
+
+ while (pagesremaining > 0) {
+ /* Update the bad block table with relative
+ * bad blocks.
+ */
+ min_offset = virtual_blk * context->block_size;
+ max_offset = min_offset + context->block_size;
+
+ if (virtual_blk == 0) {
+ set_bl_data(context,
+ bl_instance,
+ current_blk,
+ current_page,
+ bl_actual_size);
+ }
+
+ if (pagesremaining > pages_per_blk) {
+ current_blk++;
+ virtual_blk++;
+ pagesremaining -= pages_per_blk;
+ } else {
+ current_page = pagesremaining;
+ pagesremaining = 0;
+ }
+ }
+ }
+
+ /* Scan forwards to write each copy. */
+ for (bl_instance = 0; bl_instance < context->redundancy;
+ bl_instance++) {
+
+ /* Create a local copy of the BCT data */
+ buffer = malloc(pages_in_bl * context->page_size);
+ if (buffer == NULL)
+ return -ENOMEM;
+
+ memset(buffer, 0, pages_in_bl * context->page_size);
+ memcpy(buffer, bl_storage, bl_actual_size);
+ insert_padding(buffer, bl_actual_size);
+
+ pagesremaining = pages_in_bl;
+
+ GET_BL_FIELD(bl_instance, start_blk, &current_blk);
+ GET_BL_FIELD(bl_instance, start_page, &current_page);
+
+ /* Encrypt and compute hash */
+ sign_data_block(buffer,
+ bl_actual_size,
+ hash_buffer);
+ (void)context->bctlib.setbl_param(bl_instance,
+ nvbct_lib_id_bl_crypto_hash,
+ (u_int32_t*)hash_buffer,
+ context->bct);
+
+ /* Write the BCT data to the storage device,
+ * picking up ECC errors
+ */
+ src = buffer;
+
+ /* Write pages as we go. */
+ virtual_blk = 0;
+ while (pagesremaining) {
+ if (current_page == 0) {
+ /* Erase the block before writing into it. */
+ erase_block(context, current_blk);
+ }
+
+ e = write_page(context,
+ current_blk, current_page, src);
+ if (e != 0)
+ goto fail;
+ pagesremaining--;
+ src += context->page_size;
+ current_page++;
+ if (current_page >= pages_per_blk) {
+ current_page = 0;
+ current_blk++;
+ virtual_blk++;
+ }
+ context->last_bl_blk = current_blk;
+ }
+ free(buffer);
+ }
+
+ (void)context->bctlib.set_value(nvbct_lib_id_bootloader_used,
+ context->redundancy + bl_move_count,
+ context->bct);
+
+ if (enable_debug) {
+ GET_VALUE(bootloader_used, &bl_used);
+
+ for (i = 0; i < bootloaders_max; i++) {
+ u_int32_t version;
+ u_int32_t start_blk;
+ u_int32_t start_page;
+ u_int32_t length;
+ u_int32_t load_addr;
+ u_int32_t entry_point;
+
+ GET_BL_FIELD(i, version, &version);
+ GET_BL_FIELD(i, start_blk, &start_blk);
+ GET_BL_FIELD(i, start_page, &start_page);
+ GET_BL_FIELD(i, length, &length);
+ GET_BL_FIELD(i, load_addr, &load_addr);
+ GET_BL_FIELD(i, entry_point, &entry_point);
+
+ printf("%sBL[%d]: %d %04d %04d %04d 0x%08x 0x%08x k=",
+ i < bl_used ? " " : "**",
+ i,
+ version,
+ start_blk,
+ start_page,
+ length,
+ load_addr,
+ entry_point);
+
+ (void)context->bctlib.getbl_param(i,
+ nvbct_lib_id_bl_crypto_hash,
+ (u_int32_t*)hash_buffer,
+ context->bct);
+ for (j = 0; j < hash_size / 4; j++) {
+ printf("%08x",
+ *((u_int32_t*)(hash_buffer + 4*j)));
+ }
+ printf("\n");
+ }
+ }
+ free(bl_storage);
+ free(hash_buffer);
+ return 0;
+fail:
+ /* Cleanup. */
+ free(buffer);
+ free(bl_storage);
+ free(hash_buffer);
+ printf("Write bootloader failed, error: %d.\n", e);
+ return e;
+}
+
+int
+update_addon_item(build_image_context *context)
+{
+ u_int8_t *aoi_storage;
+ u_int8_t *buffer=NULL;
+ u_int8_t *src=NULL;
+ u_int32_t aoi_length;
+ u_int32_t aoi_actual_size;
+ u_int32_t pages_count;
+ u_int32_t pagesremaining;
+ u_int32_t current_blk;
+ u_int32_t current_page;
+ u_int32_t pages_per_blk;
+ u_int32_t table_length;
+ u_int32_t hash_size;
+ int i;
+ u_int8_t magicid[8] = "ChromeOs";
+ struct addon_item_rec *current_item;
+ file_type aoi_filetype = file_type_addon;
+ int e = 0;
+
+ /* Read the Addon item into memory. */
+ GET_VALUE(hash_size, &hash_size);
+ pages_per_blk = 1 << (context->block_size_log2
+ - context->page_size_log2);
+ current_blk = context->last_bl_blk;
+
+ /* Get the addon table block number */
+ current_blk++;
+ context->addon_tbl_blk = current_blk;
+
+ /* write the addon item */
+ current_item = context->addon_tbl.addon_item_list;
+ for(i = 0; i < context->addon_tbl.addon_item_no; i++) {
+
+ if (read_from_image(current_item->addon_filename,
+ context->page_size,
+ &aoi_storage,
+ &aoi_length,
+ &aoi_actual_size,
+ aoi_filetype) == 1) {
+ printf("Error reading addon file %s.\n",
+ context->addon_tbl.addon_item_list->addon_filename);
+
+ exit(1);
+ }
+ pages_count = iceil_log2(aoi_length, context->page_size_log2);
+
+ /* Create a local copy of the BCT data */
+ buffer = malloc(pages_count * context->page_size);
+ if (buffer == NULL)
+ return -ENOMEM;
+
+ memset(buffer, 0, pages_count * context->page_size);
+ memcpy(buffer, aoi_storage, aoi_actual_size);
+ insert_padding(buffer, aoi_actual_size);
+ /* Encrypt and compute hash */
+ sign_data_block(buffer,
+ aoi_actual_size,
+ (u_int8_t *)current_item->item.item_checksum);
+
+ pagesremaining = pages_count;
+ src = buffer;
+ current_blk++;
+ current_page = 0;
+ current_item->item.Location = current_blk;
+ current_item->item.size = aoi_actual_size;
+ while (pagesremaining) {
+ if (current_page == 0) {
+ /* Erase the block before writing into it. */
+ e = erase_block(context, current_blk);
+ if (e != 0)
+ goto fail_on_item;
+ }
+ e = write_page(context,
+ current_blk, current_page, src);
+ if (e != 0)
+ goto fail_on_item;
+ pagesremaining--;
+ src += context->page_size;
+ current_page++;
+ if (current_page >= pages_per_blk) {
+ current_page = 0;
+ current_blk++;
+ }
+ }
+ current_item = current_item->next;
+ free(aoi_storage);
+ free(buffer);
+ }
+
+ /* write add on table */
+ current_blk = context->addon_tbl_blk;
+ current_item = context->addon_tbl.addon_item_list;
+ current_page = 0;
+ table_length = sizeof(struct table_rec) +
+ context->addon_tbl.addon_item_no * sizeof(struct item_rec);
+ context->addon_tbl.table.table_size= table_length;
+ memcpy(context->addon_tbl.table.magic_id, magicid, 8);
+ pages_count = iceil_log2(table_length, context->page_size_log2);
+ buffer = malloc(pages_count * context->page_size);
+ if (buffer == NULL)
+ return -ENOMEM;
+
+ memset(buffer, 0, pages_count * context->page_size);
+ src = buffer;
+ memcpy(src, &context->addon_tbl, sizeof(struct table_rec));
+ src += sizeof(struct table_rec);
+
+ for(i = 0; i < context->addon_tbl.addon_item_no; i++) {
+ memcpy(src, current_item, sizeof(struct item_rec));
+ src += sizeof(struct item_rec);
+ current_item = current_item->next;
+ }
+ insert_padding(buffer, table_length);
+
+ pagesremaining = pages_count;
+ src = buffer;
+
+ /* Encrypt and compute hash */
+ e = sign_data_block(buffer,
+ table_length,
+ (u_int8_t *)context->addon_tbl.table.table_checksum);
+ if (e != 0)
+ goto fail_on_table;
+ memcpy(src+sizeof(context->addon_tbl.table.magic_id),
+ context->addon_tbl.table.table_checksum,
+ hash_size);
+
+ while (pagesremaining) {
+ if (current_page == 0) {
+ e = erase_block(context, current_blk);
+ if (e != 0)
+ goto fail_on_table;
+ }
+ e = write_page(context, current_blk, current_page, src);
+ if(e != 0)
+ goto fail_on_table;
+ pagesremaining--;
+ src += context->page_size;
+ current_page++;
+ }
+ free(buffer);
+ return 0;
+
+fail_on_item:
+ free(aoi_storage);
+
+fail_on_table:
+ free(buffer);
+ return e;
+}
+
+void
+update_context(struct build_image_context_rec *context)
+{
+ (void)context->bctlib.get_value(nvbct_lib_id_partition_size,
+ &context->partition_size,
+ context->bct);
+ (void)context->bctlib.get_value(nvbct_lib_id_page_size_log2,
+ &context->page_size_log2,
+ context->bct);
+ (void)context->bctlib.get_value(nvbct_lib_id_block_size_log2,
+ &context->block_size_log2,
+ context->bct);
+
+ context->page_size = 1 << context->page_size_log2;
+ context->block_size = 1 << context->block_size_log2;
+ context->pages_per_blk = 1 << (context->block_size_log2 -
+ context->page_size_log2);
+}
+void
+read_bct_file(struct build_image_context_rec *context)
+{
+ u_int8_t *bct_storage; /* Holds the Bl after reading */
+ u_int32_t bct_length; /* In bytes */
+ u_int32_t bct_actual_size; /* In bytes */
+ u_int32_t bct_size;
+ file_type bct_filetype = file_type_bct;
+
+ bct_size = sizeof(nvboot_config_table);
+ if (read_from_image(context->bct_filename,
+ context->page_size,
+ &bct_storage,
+ &bct_length,
+ &bct_actual_size,
+ bct_filetype) == 1) {
+ printf("Error reading bct file %s.\n", context->bct_filename);
+ exit(1);
+ }
+ memcpy(context->bct, bct_storage, bct_size);
+ free(bct_storage);
+ update_context(context);
+}
+
+void destroy_addon_list(struct addon_item_rec *addon_list)
+{
+ struct addon_item_rec *next;
+
+ while (addon_list) {
+ next = addon_list->next;
+ free(addon_list);
+ addon_list = next;
+ }
+}
+
+static void
+find_new_journal_blk(build_image_context *context)
+{
+ u_int32_t current_blk;
+ u_int32_t max_bct_search_blks;
+
+ assert(context);
+
+ current_blk = context->journal_blk;
+
+ GET_VALUE(max_bct_search_blks, &max_bct_search_blks);
+
+ if (current_blk > max_bct_search_blks) {
+ printf("Error: Unable to locate a journal block.\n");
+ exit(1);
+ }
+
+ context->journal_blk = current_blk;
+}
+
+/*
+ * Logic for updating a BCT or BL:
+ * - begin_update():
+ * - If the device is blank:
+ * - Identify & erase a journal block.
+ * - If the journal block has gone bad:
+ * - Perform an UpdateBL to move the good bootloader out of the
+ * way, if needed.
+ * - Erase the new journal block
+ * - Write the good BCT to slot 0 of the new journal block.
+ * - If the journal block is full:
+ * - Erase block 0
+ * - Write 0's to BCT slot 0.
+ * - Write the good BCT to slot 1.
+ * - Erase the journal block.
+ * - Write the good BCT to slot 0 of the journal block.
+ * - Erase block 0
+ * - If updating the BL, do so here.
+ * - finish_update():
+ * - Write the new BCT to the next available of the journal block.
+ * - Write the new BCT to slot 0 of block 0.
+ */
+
+/* - begin_update():
+ * - Test the following conditions in this order:
+ * - If the device is blank:
+ * - Identify & erase a journal block.
+ * - If the journal block has gone bad:
+ * - Perform an UpdateBL to move the good bootloader out of the
+ * way, if needed.
+ * - Erase the new journal block
+ * - Write the good BCT to slot 0 of the new journal block.
+ * - If the journal block is full:
+ * - Erase block 0
+ * - Write 0's to BCT slot 0.
+ * - Write the good BCT to slot 1.
+ * - Erase the journal block.
+ * - Write the good BCT to slot 0 of the journal block.
+ * - Erase block 0
+ */
+static int
+begin_update(build_image_context *context)
+{
+ u_int32_t pages_per_bct;
+ u_int32_t pages_per_blk;
+ u_int32_t bct_size;
+ u_int32_t hash_size;
+ u_int32_t reserved_size;
+ u_int32_t reserved_offset;
+ int e = 0;
+
+ assert(context);
+
+ /* Ensure that the BCT block & page data is current. */
+ if (enable_debug) {
+ u_int32_t block_size_log2;
+ u_int32_t page_size_log2;
+
+ GET_VALUE(block_size_log2, &block_size_log2);
+ GET_VALUE(page_size_log2, &page_size_log2);
+
+ printf("begin_update(): bct data: b=%d p=%d\n",
+ block_size_log2, page_size_log2);
+ }
+
+ GET_VALUE(bct_size, &bct_size);
+ GET_VALUE(hash_size, &hash_size);
+ GET_VALUE(reserved_size, &reserved_size);
+ GET_VALUE(reserved_offset, &reserved_offset);
+
+ pages_per_bct = iceil_log2(bct_size, context->page_size_log2);
+ pages_per_blk = (1 << (context->block_size_log2
+ - context->page_size_log2));
+
+ /* Fill the reserved data w/the padding pattern. */
+ write_padding(context->bct + reserved_offset, reserved_size);
+
+ /* Device is new */
+ /* Find the new journal block starting at block 1. */
+ find_new_journal_blk(context);
+
+ e = erase_block(context, context->journal_blk);
+ if (e != 0)
+ goto fail;
+ e = erase_block(context, 0);
+ if (e != 0)
+ goto fail;
+ return 0;
+fail:
+ printf("Erase block failed, error: %d.\n", e);
+ return e;
+}
+
+
+/*
+ * - finish_update():
+ * - Write the new BCT to the next available of the journal block.
+ * - Write the new BCT to slot 0 of block 0.
+ * For now, ignore end state.
+ */
+static int
+finish_update(build_image_context *context)
+{
+ int e = 0;
+
+ e = write_bct(context, context->journal_blk, 0);
+ if (e != 0)
+ goto fail;
+ e = write_bct(context, 0, 0);
+ if (e != 0) /* Write to block 0, slot 0. */
+ goto fail;
+ return 0;
+fail:
+ printf("Write BCT failed, error: %d.\n", e);
+ return e;
+}
+
+/*
+ * For now, ignore end state.
+ */
+int
+update_bl(build_image_context *context)
+{
+ if (enable_debug)
+ printf("**update_bl()\n");
+
+ if (begin_update(context) != 0)
+ return 1;
+ if (write_bootloaders(context) != 0)
+ return 1;
+ if (finish_update(context) != 0)
+ return 1;
+ return 0;
+}
+/*
+ * To write the current image:
+ * - Loop over all blocks in the block data list:
+ * - Write out the data of real blocks.
+ * - Write out 0's for unused blocks.
+ * - Stop on the last used page of the last used block.
+ */
+int
+write_block_raw(build_image_context *context)
+{
+ block_data *block_list;
+ block_data *block;
+ u_int32_t blk_number;
+ u_int32_t last_blk;
+ u_int32_t pages_to_write;
+ u_int8_t *data;
+ u_int8_t *empty_blk = NULL;
+
+ assert(context != NULL);
+ assert(context->memory);
+
+ block_list = context->memory;
+
+ /* Compute the end of the image. */
+ block_list = context->memory;
+ while (block_list->next)
+ block_list = block_list->next;
+
+ last_blk = block_list->blk_number;
+
+ /* Loop over all the storage from block 0, page 0 to
+ *last_blk, Lastpage
+ */
+ for (blk_number = 0; blk_number <= last_blk; blk_number++) {
+ block = find_block(blk_number, context->memory);
+ if (block) {
+ pages_to_write = (blk_number == last_blk) ?
+ block->pages_used :
+ context->pages_per_blk;
+ data = block->data;
+ } else {
+ /* Allocate empty_blk if needed. */
+ if (empty_blk == NULL) {
+ empty_blk = malloc(context->block_size);
+ if (!empty_blk)
+ return -ENOMEM;
+ memset(empty_blk, 0, context->block_size);
+ }
+ pages_to_write = context->pages_per_blk;
+ data = empty_blk;
+ }
+ /* Write the data */
+ fwrite(data, 1,
+ pages_to_write * context->page_size,
+ context->raw_file);
+ }
+
+ free(empty_blk);
+ return 0;
+}
diff --git a/system/cbootimage/data_layout.h b/system/cbootimage/data_layout.h
new file mode 100644
index 0000000..58ed9c0
--- /dev/null
+++ b/system/cbootimage/data_layout.h
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * data_layout.h - Definitions for the cbootimage data layout code.
+ */
+
+#ifndef INCLUDED_DATA_LAYOUT_H
+#define INCLUDED_DATA_LAYOUT_H
+
+#include "cbootimage.h"
+
+/* Foward declarations */
+struct build_image_context_rec;
+
+typedef struct blk_data_rec *blk_data_handle;
+
+blk_data_handle new_block_list(void);
+void destroy_block_list(blk_data_handle);
+void destroy_addon_list(struct addon_item_rec *addon_list);
+
+int
+update_bl(struct build_image_context_rec *context);
+
+void
+update_context(struct build_image_context_rec *context);
+
+void
+read_bct_file(struct build_image_context_rec *context);
+
+int
+update_addon_item(struct build_image_context_rec *context);
+
+int
+write_block_raw(struct build_image_context_rec *context);
+
+#endif /* #ifndef INCLUDED_DATA_LAYOUT_H */
diff --git a/system/cbootimage/nvaes_ref.h b/system/cbootimage/nvaes_ref.h
new file mode 100644
index 0000000..a974845
--- /dev/null
+++ b/system/cbootimage/nvaes_ref.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include "cbootimage.h"
+#include "string.h"
+
+#ifndef INCLUDED_NVAES_REF_H
+#define INCLUDED_NVAES_REF_H
+
+#define NVAES_STATECOLS 4
+#define NVAES_KEYCOLS 4
+#define NVAES_ROUNDS 10
+
+void nv_aes_expand_key(u_int8_t *key, u_int8_t *expkey);
+void nv_aes_encrypt(u_int8_t *in,
+ u_int8_t *expkey,
+ u_int8_t *out);
+
+#endif // INCLUDED_NVAES_REF_H
diff --git a/system/cbootimage/nvbctlib.h b/system/cbootimage/nvbctlib.h
new file mode 100644
index 0000000..6613fe0
--- /dev/null
+++ b/system/cbootimage/nvbctlib.h
@@ -0,0 +1,126 @@
+/**
+ * Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * nvbctlib is a library for accessing data in BCTs from different versions
+ * of the BootROM. This provides a means for one utility program to
+ * reference data which is stored differently by different versions of chips,
+ * often with the same header file names.
+ *
+ * In essence, nvbctlib.h defines an API for selecting chip versions and
+ * accessing BCT data, and a separate source file wraps the API implementation
+ * around the header files that are unique to a chip version.
+ */
+
+#ifndef INCLUDED_NVBCTLIB_H
+#define INCLUDED_NVBCTLIB_H
+
+#include <sys/types.h>
+/*
+ * nvbct_lib_id defines tokens used for querying or setting values within, or
+ * about, the BCT. These are used to identify values within structures,
+ * sizes and other properties of structures, and values for enumerated
+ * constants.
+ */
+typedef enum {
+ nvbct_lib_id_none = 0,
+
+ nvbct_lib_id_crypto_hash,
+ nvbct_lib_id_random_aes_blk,
+ nvbct_lib_id_boot_data_version,
+ nvbct_lib_id_block_size_log2,
+ nvbct_lib_id_page_size_log2,
+ nvbct_lib_id_partition_size,
+ nvbct_lib_id_bootloader_used,
+ nvbct_lib_id_bootloaders_max,
+ nvbct_lib_id_reserved,
+ nvbct_lib_id_reserved_size,
+ nvbct_lib_id_reserved_offset,
+ nvbct_lib_id_bct_size,
+ nvbct_lib_id_hash_size,
+ nvbct_lib_id_crypto_offset,
+ nvbct_lib_id_crypto_length,
+ nvbct_lib_id_max_bct_search_blks,
+
+ nvbct_lib_id_bl_version,
+ nvbct_lib_id_bl_start_blk,
+ nvbct_lib_id_bl_start_page,
+ nvbct_lib_id_bl_length,
+ nvbct_lib_id_bl_load_addr,
+ nvbct_lib_id_bl_entry_point,
+ nvbct_lib_id_bl_attribute,
+ nvbct_lib_id_bl_crypto_hash,
+
+ nvbct_lib_id_max,
+
+ nvbct_lib_id_force32 = 0x7fffffff
+
+} nvbct_lib_id;
+
+typedef int (*nvbct_lib_get_bl_param)(u_int32_t set,
+ nvbct_lib_id id,
+ u_int32_t *data,
+ u_int8_t *bct);
+typedef int (*nvbct_lib_set_bl_param)(u_int32_t set,
+ nvbct_lib_id id,
+ u_int32_t *data,
+ u_int8_t *bct);
+
+typedef int (*nvbct_lib_get_value)(nvbct_lib_id id,
+ u_int32_t *data,
+ u_int8_t *bct);
+typedef int (*nvbct_lib_set_value)(nvbct_lib_id id,
+ u_int32_t data,
+ u_int8_t *bct);
+
+/*
+ * Note: On input, *length is the size of data. On output, *length is the
+ * actual size used.
+ */
+typedef int (*nvbct_lib_get_data)(nvbct_lib_id id,
+ u_int8_t *data,
+ u_int32_t *length,
+ u_int8_t *bct);
+typedef int (*nvbct_lib_set_data)(nvbct_lib_id id,
+ u_int8_t *data,
+ u_int32_t length,
+ u_int8_t *bct);
+
+/*
+ * Structure of function pointers used to access a specific BCT variant.
+ */
+typedef struct nvbct_lib_fns_rec
+{
+ nvbct_lib_get_value get_value;
+ nvbct_lib_set_value set_value;
+
+ nvbct_lib_get_data get_data;
+ nvbct_lib_set_data set_data;
+
+ nvbct_lib_get_bl_param getbl_param;
+ nvbct_lib_set_bl_param setbl_param;
+
+} nvbct_lib_fns;
+
+void nvbct_lib_get_fns(nvbct_lib_fns *fns);
+
+#endif /* #ifndef INCLUDED_NVBCTLIB_H */
diff --git a/system/cbootimage/nvbctlib_ap20.c b/system/cbootimage/nvbctlib_ap20.c
new file mode 100644
index 0000000..2535432
--- /dev/null
+++ b/system/cbootimage/nvbctlib_ap20.c
@@ -0,0 +1,282 @@
+/**
+ * Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "nvbctlib.h"
+#include "nvboot_bct.h"
+#include "string.h"
+#include "cbootimage.h"
+
+/* nvbctlib_ap20.c: The implementation of the nvbctlib API for AP20. */
+
+/* Definitions that simplify the code which follows. */
+#define CASE_GET_BL_PARAM(x) \
+case nvbct_lib_id_bl_##x:\
+ *data = bct_ptr->bootloader[set].x; \
+ break
+
+#define CASE_SET_BL_PARAM(x) \
+case nvbct_lib_id_bl_##x:\
+ bct_ptr->bootloader[set].x = *data; \
+ break
+
+#define CASE_GET_NVU32(id) \
+case nvbct_lib_id_##id:\
+ if (bct == NULL) return -ENODATA; \
+ *data = bct_ptr->id; \
+ break
+
+#define CASE_GET_CONST(id, val) \
+case nvbct_lib_id_##id:\
+ *data = val; \
+ break
+
+#define CASE_GET_CONST_PREFIX(id, val_prefix) \
+case nvbct_lib_id_##id:\
+ *data = val_prefix##id; \
+ break
+
+#define CASE_SET_NVU32(id) \
+case nvbct_lib_id_##id:\
+ bct_ptr->id = data; \
+ break
+
+#define CASE_GET_DATA(id, size) \
+case nvbct_lib_id_##id:\
+ if (*length < size) return -ENODATA;\
+ memcpy(data, &(bct_ptr->id), size); \
+ *length = size;\
+ break
+
+#define CASE_SET_DATA(id, size) \
+case nvbct_lib_id_##id:\
+ if (length < size) return -ENODATA;\
+ memcpy(&(bct_ptr->id), data, size); \
+ break
+
+
+static int
+getbl_param(u_int32_t set,
+ nvbct_lib_id id,
+ u_int32_t *data,
+ u_int8_t *bct)
+{
+ nvboot_config_table *bct_ptr = (nvboot_config_table*)bct;
+
+ if (set >= NVBOOT_MAX_BOOTLOADERS)
+ return -ENODATA;
+ if (data == NULL || bct == NULL)
+ return -ENODATA;
+
+ switch (id) {
+ CASE_GET_BL_PARAM(version);
+ CASE_GET_BL_PARAM(start_blk);
+ CASE_GET_BL_PARAM(start_page);
+ CASE_GET_BL_PARAM(length);
+ CASE_GET_BL_PARAM(load_addr);
+ CASE_GET_BL_PARAM(entry_point);
+ CASE_GET_BL_PARAM(attribute);
+
+ case nvbct_lib_id_bl_crypto_hash:
+ memcpy(data,
+ &(bct_ptr->bootloader[set].crypto_hash),
+ sizeof(nvboot_hash));
+ break;
+
+ default:
+ return -ENODATA;
+ }
+
+ return 0;
+}
+
+/* Note: The *Data argument is to support hash data. */
+static int
+setbl_param(u_int32_t set,
+ nvbct_lib_id id,
+ u_int32_t *data,
+ u_int8_t *bct)
+{
+ nvboot_config_table *bct_ptr = (nvboot_config_table*)bct;
+
+ if (set >= NVBOOT_MAX_BOOTLOADERS)
+ return -ENODATA;
+ if (data == NULL || bct == NULL)
+ return -ENODATA;
+
+ switch (id) {
+ CASE_SET_BL_PARAM(version);
+ CASE_SET_BL_PARAM(start_blk);
+ CASE_SET_BL_PARAM(start_page);
+ CASE_SET_BL_PARAM(length);
+ CASE_SET_BL_PARAM(load_addr);
+ CASE_SET_BL_PARAM(entry_point);
+ CASE_SET_BL_PARAM(attribute);
+
+ case nvbct_lib_id_bl_crypto_hash:
+ memcpy(&(bct_ptr->bootloader[set].crypto_hash),
+ data,
+ sizeof(nvboot_hash));
+ break;
+
+ default:
+ return -ENODATA;
+ }
+
+ return 0;
+}
+
+
+static int
+bct_get_value(nvbct_lib_id id, u_int32_t *data, u_int8_t *bct)
+{
+ nvboot_config_table *bct_ptr = (nvboot_config_table*)bct;
+ nvboot_config_table samplebct; /* Used for computing offsets. */
+
+ /*
+ * Note: Not all queries require use of the BCT, so testing for a
+ * valid BCT is distributed within the code.
+ */
+ if (data == NULL)
+ return -ENODATA;
+
+ switch (id) {
+ /*
+ * Simple BCT fields
+ */
+ CASE_GET_NVU32(boot_data_version);
+ CASE_GET_NVU32(block_size_log2);
+ CASE_GET_NVU32(page_size_log2);
+ CASE_GET_NVU32(partition_size);
+ CASE_GET_NVU32(bootloader_used);
+
+ /*
+ * Constants.
+ */
+
+ CASE_GET_CONST(bootloaders_max, NVBOOT_MAX_BOOTLOADERS);
+ CASE_GET_CONST(reserved_size, NVBOOT_BCT_RESERVED_SIZE);
+
+ case nvbct_lib_id_reserved_offset:
+ *data = (u_int8_t*)&(samplebct.reserved)
+ - (u_int8_t*)&samplebct;
+ break;
+
+ case nvbct_lib_id_bct_size:
+ *data = sizeof(nvboot_config_table);
+ break;
+
+ CASE_GET_CONST(hash_size, sizeof(nvboot_hash));
+
+ case nvbct_lib_id_crypto_offset:
+ /* Offset to region in BCT to encrypt & sign */
+ *data = (u_int8_t*)&(samplebct.random_aes_blk)
+ - (u_int8_t*)&samplebct;
+ break;
+
+ case nvbct_lib_id_crypto_length:
+ /* size of region in BCT to encrypt & sign */
+ *data = sizeof(nvboot_config_table) - sizeof(nvboot_hash);
+ break;
+
+ CASE_GET_CONST(max_bct_search_blks, NVBOOT_MAX_BCT_SEARCH_BLOCKS);
+
+ default:
+ return -ENODATA;
+ }
+ return 0;
+}
+
+static int
+bct_set_value(nvbct_lib_id id, u_int32_t data, u_int8_t *bct)
+{
+ nvboot_config_table *bct_ptr = (nvboot_config_table*)bct;
+
+ if (bct == NULL)
+ return -ENODATA;
+
+ switch (id) {
+ /*
+ * Simple BCT fields
+ */
+ CASE_SET_NVU32(boot_data_version);
+ CASE_SET_NVU32(block_size_log2);
+ CASE_SET_NVU32(page_size_log2);
+ CASE_SET_NVU32(partition_size);
+ CASE_SET_NVU32(bootloader_used);
+
+ default:
+ return -ENODATA;
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * Note: On input, *length is the size of Data. On output, *length is the
+ * actual size used.
+ */
+static int
+bct_get_data(nvbct_lib_id id,
+ u_int8_t *data,
+ u_int32_t *length,
+ u_int8_t *bct)
+{
+ return 0;
+}
+
+static int
+bct_set_data(nvbct_lib_id id,
+ u_int8_t *data,
+ u_int32_t length,
+ u_int8_t *bct)
+{
+ nvboot_config_table *bct_ptr = (nvboot_config_table*)bct;
+
+ if (data == NULL || bct == NULL)
+ return -ENODATA;
+
+ switch (id) {
+
+ CASE_SET_DATA(crypto_hash, sizeof(nvboot_hash));
+
+ default:
+ return -ENODATA;
+ }
+
+ return 0;
+}
+
+
+void
+nvbct_lib_get_fns(nvbct_lib_fns *fns)
+{
+ fns->get_value = bct_get_value;
+ fns->set_value = bct_set_value;
+
+ fns->get_data = bct_get_data;
+ fns->set_data = bct_set_data;
+
+ fns->getbl_param = getbl_param;
+ fns->setbl_param = setbl_param;
+}
diff --git a/system/cbootimage/nvboot_bct.h b/system/cbootimage/nvboot_bct.h
new file mode 100644
index 0000000..734ed3b
--- /dev/null
+++ b/system/cbootimage/nvboot_bct.h
@@ -0,0 +1,151 @@
+/**
+ * Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef INCLUDED_NVBOOT_BCT_H
+#define INCLUDED_NVBOOT_BCT_H
+
+#include <sys/types.h>
+
+/**
+ * Defines the number of 32-bit words in the customer_data area of the BCT.
+ */
+#define NVBOOT_BCT_CUSTOMER_DATA_WORDS 298
+
+/**
+ * Defines the number of bytes in the customer_data area of the BCT.
+ */
+#define NVBOOT_BCT_CUSTOMER_DATA_SIZE \
+ (NVBOOT_BCT_CUSTOMER_DATA_WORDS * 4)
+
+/**
+ * Defines the number of bytes in the reserved area of the BCT.
+ */
+#define NVBOOT_BCT_RESERVED_SIZE 3
+
+/**
+ * Defines the maximum number of bootloader descriptions in the BCT.
+ */
+#define NVBOOT_MAX_BOOTLOADERS 4
+
+#define NVBOOT_BCT_USED_DATA_SIZE 534
+
+/**
+ * Defines the number of entries (bits) in the bad block table.
+ * The consequences of changing its value are as follows. Using P as the
+ * # of physical blocks in the boot loader and B as the value of this
+ * constant:
+ * B > P: There will be unused storage in the bad block table.
+ * B < P: The virtual block size will be greater than the physical block
+ * size, so the granularity of the bad block table will be less than
+ * one bit per physical block.
+ *
+ * 4096 bits is enough to represent an 8MiB partition of 2KiB blocks with one
+ * bit per block (1 virtual block = 1 physical block). This occupies 512 bytes
+ * of storage.
+ */
+#define NVBOOT_BAD_BLOCK_TABLE_SIZE 4096
+
+/**
+ * Defines the maximum number of blocks to search for BCTs.
+ *
+ * This value covers the initial block and a set of journal blocks.
+ *
+ * Ideally, this number will span several erase units for reliable updates
+ * and tolerance for blocks to become bad with use. Safe updates require
+ * a minimum of 2 erase units in which BCTs can appear.
+ *
+ * To ensure that the BCT search spans a sufficient range of configurations,
+ * the search block count has been set to 64. This allows for redundancy with
+ * a wide range of parts and provides room for greater problems in this
+ * region of the device.
+ */
+#define NVBOOT_MAX_BCT_SEARCH_BLOCKS 64
+
+/*
+ * Defines the CMAC-AES-128 hash length in 32 bit words. (128 bits = 4 words)
+ */
+enum {NVBOOT_CMAC_AES_HASH_LENGTH = 4};
+
+/**
+ * Defines the storage for a hash value (128 bits).
+ */
+typedef struct nvboot_hash_rec
+{
+ u_int32_t hash[NVBOOT_CMAC_AES_HASH_LENGTH];
+} nvboot_hash;
+
+/**
+ * Stores information needed to locate and verify a boot loader.
+ *
+ * There is one \c nv_bootloader_info structure for each copy of a BL stored on
+ * the device.
+ */
+typedef struct nv_bootloader_info_rec
+{
+ u_int32_t version;
+ u_int32_t start_blk;
+ u_int32_t start_page;
+ u_int32_t length;
+ u_int32_t load_addr;
+ u_int32_t entry_point;
+ u_int32_t attribute;
+ nvboot_hash crypto_hash;
+} nv_bootloader_info;
+
+/**
+ * Defines the bad block table structure stored in the BCT.
+ */
+typedef struct nvboot_badblock_table_rec
+{
+ u_int32_t entries_used;
+ u_int8_t virtual_blk_size_log2;
+ u_int8_t block_size_log2;
+ u_int8_t bad_blks[NVBOOT_BAD_BLOCK_TABLE_SIZE / 8];
+} nvboot_badblock_table;
+
+/**
+ * Contains the information needed to load BLs from the secondary boot device.
+ *
+ * - Supplying NumParamSets = 0 indicates not to load any of them.
+ * - Supplying NumDramSets = 0 indicates not to load any of them.
+ * - The \c random_aes_blk member exists to increase the difficulty of
+ * key attacks based on knowledge of this structure.
+ */
+typedef struct nvboot_config_table_rec
+{
+ nvboot_hash crypto_hash;
+ nvboot_hash random_aes_blk;
+ u_int32_t boot_data_version;
+ u_int32_t block_size_log2;
+ u_int32_t page_size_log2;
+ u_int32_t partition_size;
+ u_int32_t bct_used_data[NVBOOT_BCT_USED_DATA_SIZE];
+ nvboot_badblock_table badblock_table;
+ u_int32_t bootloader_used;
+ nv_bootloader_info bootloader[NVBOOT_MAX_BOOTLOADERS];
+ u_int8_t customer_data[NVBOOT_BCT_CUSTOMER_DATA_SIZE];
+ u_int8_t enable_fail_back;
+ u_int8_t reserved[NVBOOT_BCT_RESERVED_SIZE];
+} nvboot_config_table;
+
+/** @} */
+#endif /* #ifndef INCLUDED_NVBOOT_BCT_H */
diff --git a/system/cbootimage/parse.c b/system/cbootimage/parse.c
new file mode 100644
index 0000000..e52648a
--- /dev/null
+++ b/system/cbootimage/parse.c
@@ -0,0 +1,527 @@
+/**
+ * Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * parse.c - Parsing support for the cbootimage tool
+ */
+
+/*
+ * TODO / Notes
+ * - Add doxygen commentary
+ * - Do we have endian issues to deal with?
+ * - Add support for device configuration data
+ * - Add support for bad blocks
+ * - Add support for different allocation modes/strategies
+ * - Add support for multiple BCTs in journal block
+ * - Add support for other missing features.
+ */
+
+#include "parse.h"
+#include "cbootimage.h"
+#include "data_layout.h"
+#include "crypto.h"
+#include "set.h"
+
+/*
+ * Function prototypes
+ *
+ * ParseXXX() parses XXX in the input
+ * SetXXX() sets state based on the parsing results but does not perform
+ * any parsing of its own
+ * A ParseXXX() function may call other parse functions and set functions.
+ * A SetXXX() function may not call any parseing functions.
+ */
+
+static char *parse_u32(char *statement, u_int32_t *val);
+static char *parse_filename(char *statement, char *name, int chars_remaining);
+static int
+parse_array(build_image_context *context, parse_token token, char *rest);
+static int
+parse_bootloader(build_image_context *context, parse_token token, char *rest);
+static int
+parse_value_u32(build_image_context *context, parse_token token, char *rest);
+static int
+parse_bct_file(build_image_context *context, parse_token token, char *rest);
+static int
+parse_addon(build_image_context *context, parse_token token, char *rest);
+static char *parse_string(char *statement, char *uname, int chars_remaining);
+static char
+*parse_end_state(char *statement, char *uname, int chars_remaining);
+static int process_statement(build_image_context *context, char *statement);
+
+static parse_item s_top_level_items[] =
+{
+ { "Bctfile=", token_bct_file, parse_bct_file },
+ { "Attribute=", token_attribute, parse_value_u32 },
+ { "Attribute[", token_attribute, parse_array },
+ { "BootLoader=", token_bootloader, parse_bootloader },
+ { "Redundancy=", token_redundancy, parse_value_u32 },
+ { "Version=", token_version, parse_value_u32 },
+ { "AddOn[", token_addon, parse_addon },
+ { NULL, 0, NULL } /* Must be last */
+};
+
+/* Macro to simplify parser code a bit. */
+#define PARSE_COMMA(x) if (*rest != ',') return (x); rest++
+
+/* This parsing code was initially borrowed from nvcamera_config_parse.c. */
+/* Returns the address of the character after the parsed data. */
+static char *
+parse_u32(char *statement, u_int32_t *val)
+{
+ u_int32_t value = 0;
+
+ while (*statement=='0') {
+ statement++;
+ }
+
+ if (*statement=='x' || *statement=='X') {
+ statement++;
+ while (((*statement >= '0') && (*statement <= '9')) ||
+ ((*statement >= 'a') && (*statement <= 'f')) ||
+ ((*statement >= 'A') && (*statement <= 'F'))) {
+ value *= 16;
+ if ((*statement >= '0') && (*statement <= '9')) {
+ value += (*statement - '0');
+ } else if ((*statement >= 'A') &&
+ (*statement <= 'F')) {
+ value += ((*statement - 'A')+10);
+ } else {
+ value += ((*statement - 'a')+10);
+ }
+ statement++;
+ }
+ } else {
+ while (*statement >= '0' && *statement <= '9') {
+ value = value*10 + (*statement - '0');
+ statement++;
+ }
+ }
+ *val = value;
+ return statement;
+}
+
+/* This parsing code was initially borrowed from nvcamera_config_parse.c. */
+/* Returns the address of the character after the parsed data. */
+static char *
+parse_filename(char *statement, char *name, int chars_remaining)
+{
+ while (((*statement >= '0') && (*statement <= '9')) ||
+ ((*statement >= 'a') && (*statement <= 'z')) ||
+ ((*statement >= 'A') && (*statement <= 'Z')) ||
+ (*statement == '\\') ||
+ (*statement == '/' ) ||
+ (*statement == '~' ) ||
+ (*statement == '_' ) ||
+ (*statement == '-' ) ||
+ (*statement == '+' ) ||
+ (*statement == ':' ) ||
+ (*statement == '.' )) {
+ /* Check if the filename buffer is out of space, preserving one
+ * character to null terminate the string.
+ */
+ chars_remaining--;
+
+ if (chars_remaining < 1)
+ return NULL;
+ *name++ = *statement++;
+ }
+
+ /* Null terminate the filename. */
+ *name = '\0';
+
+ return statement;
+}
+
+/*
+ * parse_bootloader(): Processes commands to set a bootloader.
+ */
+static int parse_bootloader(build_image_context *context,
+ parse_token token,
+ char *rest)
+{
+ char filename[MAX_BUFFER];
+ char e_state[MAX_STR_LEN];
+ u_int32_t load_addr;
+ u_int32_t entry_point;
+
+ assert(context != NULL);
+ assert(rest != NULL);
+
+ /* Parse the file name. */
+ rest = parse_filename(rest, filename, MAX_BUFFER);
+ if (rest == NULL)
+ return 1;
+
+ PARSE_COMMA(1);
+
+ /* Parse the load address. */
+ rest = parse_u32(rest, &load_addr);
+ if (rest == NULL)
+ return 1;
+
+ PARSE_COMMA(1);
+
+ /* Parse the entry point. */
+ rest = parse_u32(rest, &entry_point);
+ if (rest == NULL)
+ return 1;
+
+ PARSE_COMMA(1);
+
+ /* Parse the end state. */
+ rest = parse_end_state(rest, e_state, MAX_STR_LEN);
+ if (rest == NULL)
+ return 1;
+ if (strncmp(e_state, "Complete", strlen("Complete")))
+ return 1;
+
+ /* Parsing has finished - set the bootloader */
+ return set_bootloader(context, filename, load_addr, entry_point);
+}
+
+/*
+ * parse_array(): Processes commands to set an array value.
+ */
+static int
+parse_array(build_image_context *context, parse_token token, char *rest)
+{
+ u_int32_t index;
+ u_int32_t value;
+
+ assert(context != NULL);
+ assert(rest != NULL);
+
+ /* Parse the index. */
+ rest = parse_u32(rest, &index);
+ if (rest == NULL)
+ return 1;
+
+ /* Parse the closing bracket. */
+ if (*rest != ']')
+ return 1;
+ rest++;
+
+ /* Parse the equals sign.*/
+ if (*rest != '=')
+ return 1;
+ rest++;
+
+ /* Parse the value based on the field table. */
+ switch(token) {
+ case token_attribute:
+ rest = parse_u32(rest, &value);
+ break;
+
+ default:
+ /* Unknown token */
+ return 1;
+ }
+
+ if (rest == NULL)
+ return 1;
+
+ /* Store the result. */
+ return context_set_array(context, index, token, value);
+}
+
+/*
+ * parse_value_u32(): General handler for setting u_int32_t values in config files.
+ */
+static int parse_value_u32(build_image_context *context,
+ parse_token token,
+ char *rest)
+{
+ u_int32_t value;
+
+ assert(context != NULL);
+ assert(rest != NULL);
+
+ rest = parse_u32(rest, &value);
+ if (rest == NULL)
+ return 1;
+
+ return context_set_value(context, token, value);
+}
+
+static int
+parse_bct_file(build_image_context *context, parse_token token, char *rest)
+{
+ char filename[MAX_BUFFER];
+
+ assert(context != NULL);
+ assert(rest != NULL);
+
+ /* Parse the file name. */
+ rest = parse_filename(rest, filename, MAX_BUFFER);
+ if (rest == NULL)
+ return 1;
+
+ /* Parsing has finished - set the bctfile */
+ context->bct_filename = filename;
+ /* Read the bct file to buffer */
+ read_bct_file(context);
+ return 0;
+}
+
+static char *
+parse_string(char *statement, char *uname, int chars_remaining)
+{
+ memset(uname, 0, chars_remaining);
+ while (((*statement >= '0') && (*statement <= '9')) ||
+ ((*statement >= 'A') && (*statement <= 'Z')) ||
+ ((*statement >= 'a') && (*statement <= 'z'))) {
+
+ *uname++ = *statement++;
+ if (--chars_remaining < 0) {
+ printf("String length beyond the boundary!!!");
+ return NULL;
+ }
+ }
+ *uname = '\0';
+ return statement;
+}
+
+static char *
+parse_end_state(char *statement, char *uname, int chars_remaining)
+{
+ while (((*statement >= 'a') && (*statement <= 'z')) ||
+ ((*statement >= 'A') && (*statement <= 'Z'))) {
+
+ *uname++ = *statement++;
+ if (--chars_remaining < 0)
+ return NULL;
+ }
+ *uname = '\0';
+ return statement;
+}
+
+
+/* Parse the addon component */
+static int
+parse_addon(build_image_context *context, parse_token token, char *rest)
+{
+ char filename[MAX_BUFFER];
+ char u_name[4];
+ char e_state[MAX_STR_LEN];
+ u_int32_t index;
+ u_int32_t item_attr;
+ u_int32_t others;
+ char other_str[MAX_STR_LEN];
+
+ assert(context != NULL);
+ assert(rest != NULL);
+
+ /* Parse the index. */
+ rest = parse_u32(rest, &index);
+ if (rest == NULL)
+ return 1;
+
+ /* Parse the closing bracket. */
+ if (*rest != ']')
+ return 1;
+ rest++;
+
+ /* Parse the equals sign.*/
+ if (*rest != '=')
+ return 1;
+ rest++;
+
+ rest = parse_filename(rest, filename, MAX_BUFFER);
+ if (rest == NULL)
+ return 1;
+ if (set_addon_filename(context, filename, index) != 0)
+ return 1;
+
+ PARSE_COMMA(1);
+
+ rest = parse_string(rest, u_name, 3);
+ if (rest == NULL) {
+ printf("Unique name should be 3 characters.\n");
+ return 1;
+ }
+ if (set_unique_name(context, u_name, index) != 0)
+ return 1;
+
+ PARSE_COMMA(1);
+
+ rest = parse_u32(rest, &item_attr);
+ if (rest == NULL)
+ return 1;
+ if (set_addon_attr(context, item_attr, index) != 0)
+ return 1;
+
+ PARSE_COMMA(1);
+
+ if (*rest == '0' && (*(rest + 1) == 'x' ||*(rest + 1) == 'X')) {
+ rest = parse_u32(rest, &others);
+ if (set_other_field(context, NULL, others, index) != 0)
+ return 1;
+ } else {
+ rest = parse_string(rest, other_str, 16);
+ if (set_other_field(context, other_str, 0, index) != 0)
+ return 1;
+ }
+ if (rest == NULL)
+ return 1;
+
+ PARSE_COMMA(1);
+
+ rest = parse_end_state(rest, e_state, MAX_STR_LEN);
+ if (rest == NULL)
+ return 1;
+ if (strncmp(e_state, "Complete", strlen("Complete")))
+ return 1;
+ return 0;
+}
+
+/* Return 0 on success, 1 on error */
+static int
+process_statement(build_image_context *context, char *statement)
+{
+ int i;
+ char *rest;
+
+ for (i = 0; s_top_level_items[i].prefix != NULL; i++) {
+ if (!strncmp(s_top_level_items[i].prefix, statement,
+ strlen(s_top_level_items[i].prefix))) {
+ rest = statement + strlen(s_top_level_items[i].prefix);
+
+ return s_top_level_items[i].process(context,
+ s_top_level_items[i].token,
+ rest);
+ }
+ }
+
+ /* If this point was reached, there was a processing error. */
+ return 1;
+}
+
+/* Note: Basic parsing borrowed from nvcamera_config.c */
+void process_config_file(build_image_context *context)
+{
+ char buffer[MAX_BUFFER];
+ int space = 0;
+ char current;
+ u_int8_t c_eol_comment_start = 0; // True after first slash
+ u_int8_t comment = 0;
+ u_int8_t string = 0;
+ u_int8_t equal_encounter = 0;
+
+ assert(context != NULL);
+ assert(context->config_file != NULL);
+
+ while ((current = fgetc(context->config_file)) !=EOF) {
+ if (space >= (MAX_BUFFER-1)) {
+ /* if we exceeded the max buffer size, it is likely
+ due to a missing semi-colon at the end of a line */
+ printf("Config file parsing error!");
+ exit(1);
+ }
+
+ /* Handle failure to complete "//" comment token.
+ Insert the '/' into the busffer and proceed with
+ processing the current character. */
+ if (c_eol_comment_start && current != '/') {
+ c_eol_comment_start = 0;
+ buffer[space++] = '/';
+ }
+
+ switch (current) {
+ case '\"': /* " indicates start or end of a string */
+ if (!comment) {
+ string ^= 1;
+ buffer[space++] = current;
+ }
+ break;
+ case ';':
+ if (!string && !comment) {
+ buffer[space++] = '\0';
+
+ /* Process a statement. */
+ if (process_statement(context, buffer)) {
+ goto error;
+ }
+ space = 0;
+ equal_encounter = 0;
+ } else if (string) {
+ buffer[space++] = current;
+ }
+ break;
+
+ case '/':
+ if (!string && !comment) {
+ if (c_eol_comment_start) {
+ /* EOL comment started. */
+ comment = 1;
+ c_eol_comment_start = 0;
+ } else {
+ /* Potential start of eol comment. */
+ c_eol_comment_start = 1;
+ }
+ } else if (!comment) {
+ buffer[space++] = current;
+ }
+ break;
+
+ /* ignore whitespace. uses fallthrough */
+ case '\n':
+ case '\r': /* carriage returns end comments */
+ string = 0;
+ comment = 0;
+ c_eol_comment_start = 0;
+ case ' ':
+ case '\t':
+ if (string) {
+ buffer[space++] = current;
+ }
+ break;
+
+ case '#':
+ if (!string) {
+ comment = 1;
+ } else {
+ buffer[space++] = current;
+ }
+ break;
+
+ default:
+ if (!comment) {
+ buffer[space++] = current;
+ if (current == '=') {
+ if (!equal_encounter) {
+ equal_encounter = 1;
+ } else {
+ goto error;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ return;
+
+ error:
+ printf("Error parsing: %s\n", buffer);
+ exit(1);
+}
diff --git a/system/cbootimage/parse.h b/system/cbootimage/parse.h
new file mode 100644
index 0000000..457b546
--- /dev/null
+++ b/system/cbootimage/parse.h
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * parse.h - Definitions for the cbootimage parsing code.
+ */
+
+/*
+ * TODO / Notes
+ * - Add doxygen commentary
+ */
+
+#ifndef INCLUDED_PARSE_H
+#define INCLUDED_PARSE_H
+
+#include "cbootimage.h"
+
+
+/*
+ * Enums
+ */
+
+typedef enum
+{
+ token_none = 0,
+ token_attribute,
+ token_bootloader,
+ token_page_size,
+ token_redundancy,
+ token_version,
+ token_bct_file,
+ token_addon,
+
+ token_force32 = 0x7fffffff
+} parse_token;
+
+/* Forward declarations */
+typedef int (*process_function)(build_image_context *context,
+ parse_token token,
+ char *Remiainder);
+
+typedef struct
+{
+ char *prefix;
+ parse_token token;
+ process_function process;
+} parse_item;
+
+/*
+ * Function prototypes
+ */
+void process_config_file(build_image_context *context);
+
+
+#endif /* #ifndef INCLUDED_PARSE_H */
diff --git a/system/cbootimage/set.c b/system/cbootimage/set.c
new file mode 100644
index 0000000..14fe214
--- /dev/null
+++ b/system/cbootimage/set.c
@@ -0,0 +1,306 @@
+/**
+ * Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * set.c - State setting support for the cbootimage tool
+ */
+
+#include "set.h"
+#include "cbootimage.h"
+#include "crypto.h"
+#include "data_layout.h"
+
+/*
+ * Function prototypes
+ *
+ * ParseXXX() parses XXX in the input
+ * SetXXX() sets state based on the parsing results but does not perform
+ * any parsing of its own
+ * A ParseXXX() function may call other parse functions and set functions.
+ * A SetXXX() function may not call any parseing functions.
+ */
+
+int
+read_from_image(char *filename,
+ u_int32_t page_size,
+ u_int8_t **image,
+ u_int32_t *storage_size,
+ u_int32_t *actual_size,
+ file_type f_type)
+{
+ int result = 0; /* 0 = success, 1 = failure */
+ FILE *fp;
+ struct stat stats;
+
+ fp = fopen(filename, "r");
+ if (fp == NULL) {
+ result = 1;
+ return result;
+ }
+
+ if (stat(filename, &stats) != 0) {
+ printf("Error: Unable to query info on bootloader path %s\n",
+ filename);
+ result = 1;
+ goto cleanup;
+ }
+
+ *actual_size = (u_int32_t)stats.st_size;
+ *storage_size =
+ (u_int32_t)(ICEIL(stats.st_size, page_size) * page_size);
+
+ if (f_type == file_type_bl) {
+ if (stats.st_size > MAX_BOOTLOADER_SIZE) {
+ printf("Error: Bootloader file %s is too large.\n",
+ filename);
+ result = 1;
+ goto cleanup;
+ }
+
+
+ /* Workaround for a bug in release 1.0 of the boot rom.
+ * Any BL whose padded size is an integral multiple of page size
+ * has its length extended by 16 bytes to bump it to end on a
+ * partial page.
+ */
+ if ((*storage_size - *actual_size) < 16) {
+ *actual_size += 16;
+ *storage_size += page_size;
+ }
+ }
+ *image = malloc(*storage_size);
+ if (*image == NULL) {
+ result = 1;
+ goto cleanup;
+ }
+
+ memset(*image, 0, *storage_size);
+
+ if (fread(*image, 1, (size_t)stats.st_size, fp) != stats.st_size) {
+ result = 1;
+ goto cleanup;
+ }
+
+cleanup:
+ fclose(fp);
+ return result;
+}
+
+
+/*
+ * set_bootloader(): Processes commands to set a bootloader.
+ */
+int
+set_bootloader(build_image_context *context,
+ char *filename,
+ u_int32_t load_addr,
+ u_int32_t entry_point)
+{
+ context->newbl_filename = filename;
+ context->newbl_load_addr = load_addr;
+ context->newbl_entry_point = entry_point;
+ return update_bl(context);
+}
+
+#define DEFAULT() \
+ default: \
+ printf("Unexpected token %d at line %d\n", \
+ token, __LINE__); \
+ return 1
+
+/*
+ * context_set_array(): Sets an array value.
+ */
+int
+context_set_array(build_image_context *context,
+ u_int32_t index,
+ parse_token token,
+ u_int32_t value)
+{
+ assert(context != NULL);
+ assert(context->bct != NULL);
+
+ switch (token) {
+ case token_attribute:
+ (void)context->bctlib.setbl_param(index,
+ nvbct_lib_id_bl_attribute,
+ &value,
+ context->bct);
+ break;
+
+ DEFAULT();
+ }
+ return 0;
+}
+
+/*
+ * context_set_value(): General handler for setting values in config files.
+ */
+int context_set_value(build_image_context *context,
+ parse_token token,
+ u_int32_t value)
+{
+ assert(context != NULL);
+
+ switch (token) {
+ case token_attribute:
+ context->newbl_attr = value;
+ break;
+
+ case token_page_size:
+ context->page_size = value;
+ break;
+ case token_redundancy:
+ context->redundancy = value;
+ break;
+
+ case token_version:
+ context->version = value;
+ break;
+
+ DEFAULT();
+ }
+
+ return 0;
+}
+
+int
+set_addon_filename(build_image_context *context,
+ char *filename,
+ int index)
+{
+
+ struct addon_item_rec **current;
+ int i;
+
+ current = &(context->addon_tbl.addon_item_list);
+
+ for(i = 0; i <= index; i++) {
+ if (*current == NULL) {
+ (*current) = malloc(sizeof(struct addon_item_rec));
+ if (*current == NULL)
+ return -ENOMEM;
+ memset((*current), 0, sizeof(struct addon_item_rec));
+ memcpy((*current)->addon_filename,
+ filename, MAX_BUFFER);
+ (*current)->item_index = index;
+ (*current)->next = NULL;
+ context->addon_tbl.addon_item_no++;
+ } else if ((*current)->item_index == index) {
+ memcpy((*current)->addon_filename,
+ filename, MAX_BUFFER);
+ } else
+ current = &((*current)->next);
+ }
+ return 0;
+}
+
+int set_addon_attr(build_image_context *context,
+ u_int32_t file_attr,
+ int index)
+{
+ struct addon_item_rec **current;
+ int i;
+
+ current = &(context->addon_tbl.addon_item_list);
+
+ for(i = 0; i <= index; i++) {
+ if (*current == NULL) {
+ (*current) = malloc(sizeof(struct addon_item_rec));
+ if (*current == NULL)
+ return -ENOMEM;
+ memset((*current), 0, sizeof(struct addon_item_rec));
+ (*current)->item.attribute= file_attr;
+ (*current)->item_index = index;
+ (*current)->next = NULL;
+ context->addon_tbl.addon_item_no++;
+ } else if ((*current)->item_index == index) {
+ (*current)->item.attribute= file_attr;
+ } else
+ current = &((*current)->next);
+ }
+ return 0;
+}
+
+int set_unique_name(build_image_context *context, char *uname, int index)
+{
+ struct addon_item_rec **current;
+ int i;
+
+ current = &(context->addon_tbl.addon_item_list);
+
+ for(i = 0; i <= index; i++) {
+ if (*current == NULL) {
+ (*current) = malloc(sizeof(struct addon_item_rec));
+ if (*current == NULL)
+ return -ENOMEM;
+ memset((*current), 0, sizeof(struct addon_item_rec));
+ memcpy((*current)->item.unique_name, uname, 4);
+ (*current)->item_index = index;
+ (*current)->next = NULL;
+ context->addon_tbl.addon_item_no++;
+ } else if ((*current)->item_index == index) {
+ memcpy((*current)->item.unique_name, uname, 4);
+ } else
+ current = &((*current)->next);
+ }
+ return 0;
+}
+
+int
+set_other_field(build_image_context *context,
+ char *other_str,
+ int other,
+ int index)
+{
+ struct addon_item_rec **current;
+ int i;
+
+ current = &(context->addon_tbl.addon_item_list);
+
+ for(i = 0; i <= index; i++) {
+ if (*current == NULL) {
+ (*current) = malloc(sizeof(struct addon_item_rec));
+ if (*current == NULL)
+ return -ENOMEM;
+ memset((*current), 0, sizeof(struct addon_item_rec));
+ if (other_str == NULL)
+ (*current)->item.reserve[0] = other;
+ else
+ memcpy((*current)->item.reserve,
+ other_str, 16);
+ (*current)->item_index = index;
+ (*current)->next = NULL;
+ context->addon_tbl.addon_item_no++;
+ } else if ((*current)->item_index == index) {
+ if (other_str == NULL)
+ (*current)->item.reserve[0] = other;
+ else
+ memcpy((*current)->item.reserve,
+ other_str, 16);
+ } else
+ current = &((*current)->next);
+ }
+ return 0;
+
+}
+
diff --git a/system/cbootimage/set.h b/system/cbootimage/set.h
new file mode 100644
index 0000000..44443f8
--- /dev/null
+++ b/system/cbootimage/set.h
@@ -0,0 +1,81 @@
+/**
+ * Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * set.h - Definitions for the cbootimage state setting code.
+ */
+
+#ifndef INCLUDED_SET_H
+#define INCLUDED_SET_H
+
+#include "cbootimage.h"
+#include "parse.h"
+#include "string.h"
+#include "sys/stat.h"
+
+int
+context_set_array(build_image_context *context,
+ u_int32_t index,
+ parse_token token,
+ u_int32_t value);
+
+int
+set_bootloader(build_image_context *context,
+ char *filename,
+ u_int32_t load_addr,
+ u_int32_t entry_point);
+
+int
+context_set_value(build_image_context *context,
+ parse_token token,
+ u_int32_t value);
+
+int
+set_addon_filename(build_image_context *context,
+ char *filename,
+ int index);
+
+int
+set_addon_attr(build_image_context *context,
+ u_int32_t file_attr,
+ int index);
+
+int
+set_unique_name(build_image_context *context,
+ char *uname,
+ int index);
+
+int
+set_other_field(build_image_context *context,
+ char *other_str,
+ int other,
+ int index);
+
+int
+read_from_image(char *filename,
+ u_int32_t page_size,
+ u_int8_t **Image,
+ u_int32_t *storage_size,
+ u_int32_t *actual_size,
+ file_type f_type);
+
+#endif /* #ifndef INCLUDED_SET_H */