Skip to content

Commit

Permalink
Add support for compressed early TAs
Browse files Browse the repository at this point in the history
Add decompression code to the early TA loader and update the Python
script accordingly. The compression algorithm is "deflate", which is
used by zlib and gzip in particular. It allows for compression ratios
comprised between 3 (for bigger TAs) and 4.7 (for smaller ones). Those
numbers were observed with 32-bit TAs (QEMU).

On QEMU (armv7), the code size overhead when CFG_EARLY_TA=y, including
the decompressor, is 12K when DEBUG=0 or 20K when DEBUG=1. The
decompressor allocates about 39K of heap.

Another library compatible with zlib was tried for comparison [1].
The code size overhead with miniz was 8K (DEBUG=0) or 16K (DEBUG=1).
On the other hand, the dynamic allocation was about 43K, so the total
memory required was about same. Speed was not compared. In the end,
zlib was preferred for licensing reasons and because it is widely used.

Link: [1] https://github.com/richgel999/miniz
Signed-off-by: Jerome Forissier <jerome.forissier@linaro.org>
Tested-by: Jerome Forissier <jerome.forissier@linaro.org> (QEMU)
Tested-by: Jerome Forissier <jerome.forissier@linaro.org> (QEMUv8, pager)
Tested-by: Jerome Forissier <jerome.forissier@linaro.org> (D02 32/64 bits)
Tested-by: Jerome Forissier <jerome.forissier@linaro.org> (D02 32/64 bits, pager)
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org>
  • Loading branch information
jforissier committed Aug 25, 2017
1 parent b3be2f6 commit 509a980
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 22 deletions.
1 change: 1 addition & 0 deletions core/arch/arm/include/kernel/early_ta.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
struct early_ta {
TEE_UUID uuid;
uint32_t size;
uint32_t uncompressed_size; /* 0: not compressed */
const uint8_t ta[]; /* @size bytes */
};

Expand Down
144 changes: 137 additions & 7 deletions core/arch/arm/kernel/early_ta.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,18 @@
#include <kernel/early_ta.h>
#include <kernel/linker.h>
#include <kernel/user_ta.h>
#include <stdio.h>
#include <string.h>
#include <trace.h>
#include <util.h>
#include <zlib.h>

#include "elf_load.h"

struct user_ta_store_handle {
const struct early_ta *early_ta;
size_t offs;
z_stream strm;
};

#define for_each_early_ta(_ta) \
Expand All @@ -56,11 +59,41 @@ static const struct early_ta *find_early_ta(const TEE_UUID *uuid)
return NULL;
}

static void *zalloc(void *opaque __unused, unsigned int items,
unsigned int size)
{
return malloc(items * size);
}

static void zfree(void *opaque __unused, void *address)
{
free(address);
}

static bool decompression_init(z_stream *strm,
const struct early_ta *ta)
{
int st;

strm->next_in = ta->ta;
strm->avail_in = ta->size;
strm->zalloc = zalloc;
strm->zfree = zfree;
st = inflateInit(strm);
if (st != Z_OK) {
EMSG("Decompression initialization error (%d)", st);
return false;
}

return true;
}

static TEE_Result early_ta_open(const TEE_UUID *uuid,
struct user_ta_store_handle **h)
{
const struct early_ta *ta;
struct user_ta_store_handle *handle;
const struct early_ta *ta;
bool st;

ta = find_early_ta(uuid);
if (!ta)
Expand All @@ -70,6 +103,13 @@ static TEE_Result early_ta_open(const TEE_UUID *uuid,
if (!handle)
return TEE_ERROR_OUT_OF_MEMORY;

if (ta->uncompressed_size) {
st = decompression_init(&handle->strm, ta);
if (!st) {
free(handle);
return TEE_ERROR_BAD_FORMAT;
}
}
handle->early_ta = ta;
*h = handle;

Expand All @@ -79,12 +119,18 @@ static TEE_Result early_ta_open(const TEE_UUID *uuid,
static TEE_Result early_ta_get_size(const struct user_ta_store_handle *h,
size_t *size)
{
*size = h->early_ta->size;
const struct early_ta *ta = h->early_ta;

if (ta->uncompressed_size)
*size = ta->uncompressed_size;
else
*size = ta->size;

return TEE_SUCCESS;
}

static TEE_Result early_ta_read(struct user_ta_store_handle *h, void *data,
size_t len)
static TEE_Result read_uncompressed(struct user_ta_store_handle *h, void *data,
size_t len)
{
uint8_t *src = (uint8_t *)h->early_ta->ta + h->offs;

Expand All @@ -97,8 +143,83 @@ static TEE_Result early_ta_read(struct user_ta_store_handle *h, void *data,
return TEE_SUCCESS;
}

static TEE_Result read_compressed(struct user_ta_store_handle *h, void *data,
size_t len)
{
z_stream *strm = &h->strm;
size_t total = 0;
uint8_t *tmpbuf = NULL;
TEE_Result ret;
size_t out;
int st;

if (data) {
strm->next_out = data;
strm->avail_out = len;
} else {
/*
* inflate() does not support a NULL strm->next_out. So, to
* discard data, we have to allocate a temporary buffer. 1K
* seems reasonable.
*/
strm->avail_out = MIN(len, 1024U);
tmpbuf = malloc(strm->avail_out);
if (!tmpbuf) {
EMSG("Out of memory");
return TEE_ERROR_OUT_OF_MEMORY;
}
strm->next_out = tmpbuf;
}
/*
* Loop until we get as many bytes as requested, or an error occurs.
* inflate() returns:
* - Z_OK when progress was made, but neither the end of the input
* stream nor the end of the output buffer were met.
* - Z_STREAM_END when the end of the intput stream was reached.
* - Z_BUF_ERROR when there is still input to process but the output
* buffer is full (not a "hard" error, decompression can proceeed
* later).
*/
do {
out = strm->total_out;
st = inflate(strm, Z_SYNC_FLUSH);
out = strm->total_out - out;
total += out;
FMSG("%zu bytes", out);
if (!data) {
/*
* Reset the pointer to throw away what we've just read
* and read again as much as possible.
*/
strm->next_out = tmpbuf;
strm->avail_out = MIN(len - total, 1024U);
}
} while ((st == Z_OK || st == Z_BUF_ERROR) && (total != len));
if (st != Z_OK && st != Z_STREAM_END) {
EMSG("Decompression error (%d)", st);
ret = TEE_ERROR_GENERIC;
goto out;
}
ret = TEE_SUCCESS;
out:
free(tmpbuf);

return ret;
}

static TEE_Result early_ta_read(struct user_ta_store_handle *h, void *data,
size_t len)
{
if (h->early_ta->uncompressed_size)
return read_compressed(h, data, len);
else
return read_uncompressed(h, data, len);
}

static void early_ta_close(struct user_ta_store_handle *h)
{
if (h->early_ta->uncompressed_size)
inflateEnd(&h->strm);
free(h);
}

Expand All @@ -114,9 +235,18 @@ static struct user_ta_store_ops ops = {
static TEE_Result early_ta_init(void)
{
const struct early_ta *ta;

for_each_early_ta(ta)
DMSG("Early TA %pUl size %u", (void *)&ta->uuid, ta->size);
char __maybe_unused msg[60] = { '\0', };

for_each_early_ta(ta) {
if (ta->uncompressed_size)
snprintf(msg, sizeof(msg),
" (compressed, uncompressed %u)",
ta->uncompressed_size);
else
msg[0] = '\0';
DMSG("Early TA %pUl size %u%s", (void *)&ta->uuid, ta->size,
msg);
}

return tee_ta_register_ta_store(&ops);
}
Expand Down
1 change: 0 additions & 1 deletion core/lib/zlib/sub.mk
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,3 @@ srcs-y += inftrees.c
srcs-y += zutil.c
cflags-remove-y += -Wold-style-definition
cflags-remove-y += -Wswitch-default
cflags-y += -DZ_SOLO=1 -DNO_GZIP=1 # No gz stuff
4 changes: 4 additions & 0 deletions core/lib/zlib/zconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
#ifndef ZCONF_H
#define ZCONF_H

#define Z_SOLO
#define ZLIB_CONST
#define NO_GZIP

/*
* If you *really* need a unique prefix for all types and library functions,
* compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
Expand Down
2 changes: 1 addition & 1 deletion core/sub.mk
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ early-ta-$1-uuid := $(firstword $(subst ., ,$(notdir $1)))
gensrcs-y += early-ta-$1
produce-early-ta-$1 = early_ta_$$(early-ta-$1-uuid).c
depends-early-ta-$1 = $1 scripts/ta_bin_to_c.py
recipe-early-ta-$1 = scripts/ta_bin_to_c.py --ta $1 \
recipe-early-ta-$1 = scripts/ta_bin_to_c.py --compress --ta $1 \
--out $(sub-dir-out)/early_ta_$$(early-ta-$1-uuid).c
cleanfiles += $(sub-dir-out)/early_ta_$$(early-ta-$1-uuid).c
endef
Expand Down
3 changes: 3 additions & 0 deletions mk/config.mk
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ $(call force,CFG_EARLY_TA,y)
else
CFG_EARLY_TA ?= n
endif
ifeq ($(CFG_EARLY_TA),y)
$(call force,CFG_ZLIB,y)
endif

# Enable paging, requires SRAM, can't be enabled by default
CFG_WITH_PAGER ?= n
Expand Down
38 changes: 25 additions & 13 deletions scripts/ta_bin_to_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import os
import re
import uuid
import zlib

def get_args():

Expand All @@ -45,6 +46,10 @@ def get_args():
help='Path to the TA binary. File name has to be: <uuid>.* '
'such as: 8aaaf200-2450-11e4-abe2-0002a5d5c51b.stripped.elf')

parser.add_argument('--compress', dest="compress",
action="store_true", help='Compress the TA using the DEFLATE '
'algorithm')

return parser.parse_args()

def main():
Expand All @@ -53,6 +58,13 @@ def main():

ta_uuid = uuid.UUID(re.sub('\..*', '', os.path.basename(args.ta)))

with open(args.ta, 'rb') as ta:
bytes = ta.read()
uncompressed_size = len(bytes)
if args.compress:
bytes = zlib.compress(bytes)
size = len(bytes)

f = open(args.out, 'w')
f.write('/* Generated from ' + args.ta + ' by ' +
os.path.basename(__file__) + ' */\n\n')
Expand All @@ -72,21 +84,21 @@ def main():
f.write('\t\t\t')
f.write(', '.join('0x' + csn[i:i+2] for i in range(0, len(csn), 2)))
f.write('\n\t\t},\n\t},\n')
f.write('\t.size = {:d},'.format(os.path.getsize(args.ta)))
f.write('\t.size = {:d},\n'.format(size))
if args.compress:
f.write('\t.uncompressed_size = '
'{:d},\n'.format(uncompressed_size))
f.write('\t.ta = {\n')
i = 0
with open(args.ta, 'rb') as ta:
byte = ta.read(1)
while byte:
if i % 8 == 0:
f.write('\t\t');
f.write('0x' + '{:02x}'.format(ord(byte)) + ',')
i = i + 1
byte = ta.read(1)
if i % 8 == 0 or not byte:
f.write('\n')
else:
f.write(' ')
while i < size:
if i % 8 == 0:
f.write('\t\t');
f.write('0x' + '{:02x}'.format(ord(bytes[i])) + ',')
i = i + 1
if i % 8 == 0 or i == size:
f.write('\n')
else:
f.write(' ')
f.write('\t},\n')
f.write('};\n');
f.close()
Expand Down

0 comments on commit 509a980

Please sign in to comment.