json: Provide a way to convert JSON to FDT
JSON is a rather more free format than devicetree, so it is sometimes better to parse it into dtb format. This is widely used in U-Boot and we can use the ofnode interface to access it. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com>
This commit is contained in:
337
test/lib/json.c
337
test/lib/json.c
@@ -1,12 +1,16 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Tests for JSON pretty-printer
|
||||
* Tests for JSON utilities including parser and FDT converter
|
||||
*
|
||||
* Copyright (C) 2025 Canonical Ltd
|
||||
* Written by Simon Glass <simon.glass@canonical.com>
|
||||
*/
|
||||
|
||||
#include <dm/ofnode.h>
|
||||
#include <fdt_support.h>
|
||||
#include <image.h>
|
||||
#include <json.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <test/lib.h>
|
||||
#include <test/test.h>
|
||||
#include <test/ut.h>
|
||||
@@ -209,3 +213,334 @@ static int lib_test_json_whitespace(struct unit_test_state *uts)
|
||||
return 0;
|
||||
}
|
||||
LIB_TEST(lib_test_json_whitespace, UTF_CONSOLE);
|
||||
|
||||
/* JSON to FDT conversion tests */
|
||||
|
||||
static int lib_test_json_to_fdt_simple(struct unit_test_state *uts)
|
||||
{
|
||||
const char *json = "{\"name\":\"test\",\"value\":42}";
|
||||
struct abuf buf;
|
||||
void *fdt_buf;
|
||||
|
||||
ut_assertok(json_to_fdt(json, &buf));
|
||||
|
||||
fdt_buf = abuf_data(&buf);
|
||||
|
||||
/* Verify FDT is valid */
|
||||
ut_assertok(fdt_check_header(fdt_buf));
|
||||
|
||||
/* Check string property */
|
||||
ut_asserteq_str("test", fdt_getprop(fdt_buf, 0, "name", NULL));
|
||||
|
||||
/* Check integer property */
|
||||
ut_asserteq(42, fdtdec_get_int(fdt_buf, 0, "value", 0));
|
||||
|
||||
abuf_uninit(&buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
LIB_TEST(lib_test_json_to_fdt_simple, 0);
|
||||
|
||||
static int lib_test_json_to_fdt_nested(struct unit_test_state *uts)
|
||||
{
|
||||
const char *json = "{\"outer\":{\"inner\":\"value\"}}";
|
||||
struct abuf buf;
|
||||
void *fdt_buf;
|
||||
int node;
|
||||
|
||||
ut_assertok(json_to_fdt(json, &buf));
|
||||
|
||||
fdt_buf = abuf_data(&buf);
|
||||
|
||||
/* Verify FDT is valid */
|
||||
ut_assertok(fdt_check_header(fdt_buf));
|
||||
|
||||
/* Find nested node */
|
||||
node = fdt_path_offset(fdt_buf, "/outer");
|
||||
ut_assert(node >= 0);
|
||||
|
||||
/* Check property in nested node */
|
||||
ut_asserteq_str("value", fdt_getprop(fdt_buf, node, "inner", NULL));
|
||||
|
||||
abuf_uninit(&buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
LIB_TEST(lib_test_json_to_fdt_nested, 0);
|
||||
|
||||
static int lib_test_json_to_fdt_array(struct unit_test_state *uts)
|
||||
{
|
||||
const char *json = "{\"numbers\":[1,2,3]}";
|
||||
struct abuf buf;
|
||||
void *fdt_buf;
|
||||
u32 arr[8];
|
||||
int size;
|
||||
oftree tree;
|
||||
ofnode root;
|
||||
|
||||
ut_assertok(json_to_fdt(json, &buf));
|
||||
|
||||
fdt_buf = abuf_data(&buf);
|
||||
|
||||
/* Verify FDT is valid */
|
||||
ut_assertok(fdt_check_header(fdt_buf));
|
||||
|
||||
/* Create oftree from FDT */
|
||||
tree = oftree_from_fdt(fdt_buf);
|
||||
ut_assert(oftree_valid(tree));
|
||||
|
||||
root = oftree_root(tree);
|
||||
ut_assert(ofnode_valid(root));
|
||||
|
||||
/* Check array property */
|
||||
ut_assertnonnull(ofnode_get_property(root, "numbers", &size));
|
||||
size /= sizeof(u32);
|
||||
ut_asserteq(3, size);
|
||||
ut_assertok(ofnode_read_u32_array(root, "numbers", arr, size));
|
||||
ut_asserteq(1, arr[0]);
|
||||
ut_asserteq(2, arr[1]);
|
||||
ut_asserteq(3, arr[2]);
|
||||
|
||||
abuf_uninit(&buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
LIB_TEST(lib_test_json_to_fdt_array, 0);
|
||||
|
||||
static int lib_test_json_to_fdt_string_array(struct unit_test_state *uts)
|
||||
{
|
||||
char json[] = "{\"tags\":[\"first\",\"second\",\"third\"]}";
|
||||
struct abuf buf;
|
||||
void *fdt_buf;
|
||||
const char *str;
|
||||
ofnode root;
|
||||
oftree tree;
|
||||
|
||||
ut_assertok(json_to_fdt(json, &buf));
|
||||
|
||||
fdt_buf = abuf_data(&buf);
|
||||
|
||||
/* Verify FDT is valid */
|
||||
ut_assertok(fdt_check_header(fdt_buf));
|
||||
|
||||
/* Create oftree from FDT */
|
||||
tree = oftree_from_fdt(fdt_buf);
|
||||
ut_assert(oftree_valid(tree));
|
||||
|
||||
root = oftree_root(tree);
|
||||
ut_assert(ofnode_valid(root));
|
||||
|
||||
/* Check string array property */
|
||||
ut_assertok(ofnode_read_string_index(root, "tags", 0, &str));
|
||||
ut_asserteq_str("first", str);
|
||||
ut_assertok(ofnode_read_string_index(root, "tags", 1, &str));
|
||||
ut_asserteq_str("second", str);
|
||||
ut_assertok(ofnode_read_string_index(root, "tags", 2, &str));
|
||||
ut_asserteq_str("third", str);
|
||||
|
||||
abuf_uninit(&buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
LIB_TEST(lib_test_json_to_fdt_string_array, 0);
|
||||
|
||||
static int lib_test_json_to_fdt_bool(struct unit_test_state *uts)
|
||||
{
|
||||
const char *json = "{\"enabled\":true,\"disabled\":false}";
|
||||
struct abuf buf;
|
||||
void *fdt_buf;
|
||||
|
||||
ut_assertok(json_to_fdt(json, &buf));
|
||||
|
||||
fdt_buf = abuf_data(&buf);
|
||||
|
||||
/* Verify FDT is valid */
|
||||
ut_assertok(fdt_check_header(fdt_buf));
|
||||
|
||||
/* Check boolean properties */
|
||||
ut_asserteq(1, fdtdec_get_int(fdt_buf, 0, "enabled", 0));
|
||||
ut_asserteq(0, fdtdec_get_int(fdt_buf, 0, "disabled", 0));
|
||||
|
||||
abuf_uninit(&buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
LIB_TEST(lib_test_json_to_fdt_bool, 0);
|
||||
|
||||
/* Test with realistic LUKS2 JSON metadata using ofnode API */
|
||||
static int lib_test_json_to_fdt_luks2(struct unit_test_state *uts)
|
||||
{
|
||||
/* Simplified LUKS2 JSON metadata structure */
|
||||
const char *luks2_json =
|
||||
"{"
|
||||
" \"keyslots\": {"
|
||||
" \"0\": {"
|
||||
" \"type\": \"luks2\","
|
||||
" \"key_size\": 32,"
|
||||
" \"area\": {"
|
||||
" \"type\": \"raw\","
|
||||
" \"offset\": \"32768\","
|
||||
" \"size\": \"258048\""
|
||||
" },"
|
||||
" \"kdf\": {"
|
||||
" \"type\": \"pbkdf2\","
|
||||
" \"hash\": \"sha256\","
|
||||
" \"iterations\": 1000,"
|
||||
" \"salt\": \"aGVsbG93b3JsZA==\""
|
||||
" }"
|
||||
" },"
|
||||
" \"1\": {"
|
||||
" \"type\": \"luks2\","
|
||||
" \"key_size\": 32,"
|
||||
" \"area\": {"
|
||||
" \"type\": \"raw\","
|
||||
" \"offset\": \"290816\","
|
||||
" \"size\": \"258048\""
|
||||
" },"
|
||||
" \"kdf\": {"
|
||||
" \"type\": \"pbkdf2\","
|
||||
" \"hash\": \"sha256\","
|
||||
" \"iterations\": 2000,"
|
||||
" \"salt\": \"YW5vdGhlcnNhbHQ=\""
|
||||
" }"
|
||||
" }"
|
||||
" },"
|
||||
" \"segments\": {"
|
||||
" \"0\": {"
|
||||
" \"type\": \"crypt\","
|
||||
" \"offset\": \"16777216\","
|
||||
" \"size\": \"dynamic\","
|
||||
" \"iv_tweak\": \"0\","
|
||||
" \"encryption\": \"aes-cbc-essiv:sha256\","
|
||||
" \"sector_size\": 512"
|
||||
" }"
|
||||
" },"
|
||||
" \"digests\": {"
|
||||
" \"0\": {"
|
||||
" \"type\": \"pbkdf2\","
|
||||
" \"keyslots\": [0, 1],"
|
||||
" \"segments\": [0],"
|
||||
" \"hash\": \"sha256\","
|
||||
" \"iterations\": 1000,"
|
||||
" \"salt\": \"c2FsdHlzYWx0\""
|
||||
" }"
|
||||
" },"
|
||||
" \"config\": {"
|
||||
" \"json_size\": \"12288\","
|
||||
" \"keyslots_size\": \"3145728\""
|
||||
" }"
|
||||
"}";
|
||||
|
||||
ofnode segments, segment0, digests, digest0, config;
|
||||
ofnode root, keyslots, keyslot0, kdf;
|
||||
struct abuf buf;
|
||||
u32 arr[8];
|
||||
int size;
|
||||
void *fdt_buf;
|
||||
oftree tree;
|
||||
|
||||
ut_assertok(json_to_fdt(luks2_json, &buf));
|
||||
|
||||
/* Verify FDT is valid */
|
||||
fdt_buf = abuf_data(&buf);
|
||||
ut_assertok(fdt_check_header(fdt_buf));
|
||||
|
||||
/* Create oftree from FDT */
|
||||
tree = oftree_from_fdt(fdt_buf);
|
||||
ut_assert(oftree_valid(tree));
|
||||
|
||||
/* Get root node */
|
||||
root = oftree_root(tree);
|
||||
ut_assert(ofnode_valid(root));
|
||||
|
||||
/* Navigate to keyslots node */
|
||||
keyslots = ofnode_find_subnode(root, "keyslots");
|
||||
ut_assert(ofnode_valid(keyslots));
|
||||
|
||||
/* Navigate to keyslot 0 */
|
||||
keyslot0 = ofnode_find_subnode(keyslots, "0");
|
||||
ut_assert(ofnode_valid(keyslot0));
|
||||
|
||||
/* Check keyslot type */
|
||||
ut_asserteq_str("luks2", ofnode_read_string(keyslot0, "type"));
|
||||
|
||||
/* Check key_size */
|
||||
ut_asserteq(32, ofnode_read_u32_default(keyslot0, "key_size", 0));
|
||||
|
||||
/* Navigate to KDF node */
|
||||
kdf = ofnode_find_subnode(keyslot0, "kdf");
|
||||
ut_assert(ofnode_valid(kdf));
|
||||
|
||||
/* Check KDF type */
|
||||
ut_asserteq_str("pbkdf2", ofnode_read_string(kdf, "type"));
|
||||
|
||||
/* Check KDF hash */
|
||||
ut_asserteq_str("sha256", ofnode_read_string(kdf, "hash"));
|
||||
|
||||
/* Check iterations */
|
||||
ut_asserteq(1000, ofnode_read_u32_default(kdf, "iterations", 0));
|
||||
|
||||
/* Check salt (base64 string) */
|
||||
ut_asserteq_str("aGVsbG93b3JsZA==", ofnode_read_string(kdf, "salt"));
|
||||
|
||||
/* Navigate to segments node */
|
||||
segments = ofnode_find_subnode(root, "segments");
|
||||
ut_assert(ofnode_valid(segments));
|
||||
|
||||
/* Navigate to segment 0 */
|
||||
segment0 = ofnode_find_subnode(segments, "0");
|
||||
ut_assert(ofnode_valid(segment0));
|
||||
|
||||
/* Check segment type */
|
||||
ut_asserteq_str("crypt", ofnode_read_string(segment0, "type"));
|
||||
|
||||
/* Check encryption */
|
||||
ut_asserteq_str("aes-cbc-essiv:sha256", ofnode_read_string(segment0, "encryption"));
|
||||
|
||||
/* Check offset (stored as string in JSON) */
|
||||
ut_asserteq_str("16777216", ofnode_read_string(segment0, "offset"));
|
||||
|
||||
/* Check sector_size */
|
||||
ut_asserteq(512, ofnode_read_u32_default(segment0, "sector_size", 0));
|
||||
|
||||
/* Navigate to digests node */
|
||||
digests = ofnode_find_subnode(root, "digests");
|
||||
ut_assert(ofnode_valid(digests));
|
||||
|
||||
/* Navigate to digest 0 */
|
||||
digest0 = ofnode_find_subnode(digests, "0");
|
||||
ut_assert(ofnode_valid(digest0));
|
||||
|
||||
/* Check digest type */
|
||||
ut_asserteq_str("pbkdf2", ofnode_read_string(digest0, "type"));
|
||||
|
||||
/* Check keyslots array */
|
||||
ut_assertnonnull(ofnode_get_property(digest0, "keyslots", &size));
|
||||
size /= sizeof(u32);
|
||||
ut_asserteq(2, size);
|
||||
ut_assertok(ofnode_read_u32_array(digest0, "keyslots", arr, size));
|
||||
ut_asserteq(0, arr[0]);
|
||||
ut_asserteq(1, arr[1]);
|
||||
|
||||
/* Check segments array */
|
||||
ut_assertnonnull(ofnode_get_property(digest0, "segments", &size));
|
||||
ut_asserteq(4, size);
|
||||
size /= sizeof(u32);
|
||||
ut_assertok(ofnode_read_u32_array(digest0, "segments", arr, size));
|
||||
ut_asserteq(0, arr[0]);
|
||||
|
||||
/* Navigate to config node */
|
||||
config = ofnode_find_subnode(root, "config");
|
||||
ut_assert(ofnode_valid(config));
|
||||
|
||||
/* Check json_size (stored as string in JSON) */
|
||||
ut_asserteq_str("12288", ofnode_read_string(config, "json_size"));
|
||||
|
||||
/* Check keyslots_size (stored as string in JSON) */
|
||||
ut_asserteq_str("3145728", ofnode_read_string(config, "keyslots_size"));
|
||||
|
||||
abuf_uninit(&buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
LIB_TEST(lib_test_json_to_fdt_luks2, 0);
|
||||
|
||||
Reference in New Issue
Block a user