/* * Copyright (c) 2022 Google Inc. All rights reserved * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #define DT_PORT "com.android.kernel.device_tree" #define DTB_PORT "com.android.trusty.kernel.device_tree.blob" static struct ktipc_server dtb_ktipc_server = KTIPC_SERVER_INITIAL_VALUE(dtb_ktipc_server, "dtb_ktipc_server"); static int find_dtb_by_compatible(const char* compat, const void** dtb, size_t* dtb_size) { assert(dtb); assert(dtb_size); int rc; const void* current_dtb = NULL; size_t current_dtb_size = 0; struct dtb_embedded_iterator* iter; rc = dtb_embedded_iterator_new(&iter); if (rc != NO_ERROR) { return rc; } for (;;) { rc = dtb_embedded_iterator_next(iter, ¤t_dtb, ¤t_dtb_size); if (rc != NO_ERROR) { break; } int test_node_offset = fdt_node_offset_by_compatible( current_dtb, -1 /* search from the start of the dtb */, compat); if (test_node_offset >= 0) { /* Found the test node */ *dtb = current_dtb; *dtb_size = current_dtb_size; break; } } dtb_embedded_iterator_free(&iter); return rc; } static void* apply_test_overlay(const void* base_dtb, size_t base_dtb_size, const void* test_dtbo, size_t test_dtbo_size) { /* Overestimate the size needed for the full dtb for now */ size_t full_size = base_dtb_size + test_dtbo_size; void* base = calloc(1, full_size); if (!base) { goto alloc_base; } /* * libfdt overwrites part of the dtbo header if applying the overlay fails * so we have to make a temporary copy since the original dtbo is in * read-only memory. */ void* overlay = calloc(1, test_dtbo_size); if (!overlay) { goto alloc_overlay; } /* * Using fdt_open_into copies the dtb to the buffer allocated above and * updates the fdt header with the new buffer size */ int rc = fdt_open_into(base_dtb, base, full_size); if (rc < 0) { TRACEF("fdt_open_into failed for base dtb (%d)\n", rc); goto copy_base; } rc = fdt_open_into(test_dtbo, overlay, test_dtbo_size); if (rc < 0) { TRACEF("fdt_open_into failed for test dtb overlay (%d)\n", rc); goto copy_overlay; } rc = fdt_overlay_apply(base, overlay); if (rc < 0) { TRACEF("Failed to apply test overlay to base dtb (%d)\n", rc); goto apply_overlay; } free(overlay); return base; apply_overlay: copy_overlay: copy_base: free(overlay); alloc_overlay: free(base); alloc_base: return NULL; } static void platform_dtb_init(uint level) { int rc; rc = ktipc_server_start(&dtb_ktipc_server); if (rc < 0) { panic("Failed (%d) to start dtb server\n", rc); } const void* base_dtb = NULL; const void* test_dtbo = NULL; size_t base_dtb_size, test_dtbo_size = 0; rc = find_dtb_by_compatible("google,test_base", &base_dtb, &base_dtb_size); if (rc != NO_ERROR) { panic("No embedded base dtb found (%d)\n", rc); } rc = find_dtb_by_compatible("google,test_overlay", &test_dtbo, &test_dtbo_size); if (rc != NO_ERROR) { panic("No embedded test dtbo found (%d)\n", rc); } const void* dtb = apply_test_overlay(base_dtb, base_dtb_size, test_dtbo, test_dtbo_size); if (!dtb) { panic("Failed to apply test overlay to base dtb\n"); } size_t dtb_size = fdt_totalsize(dtb); rc = dtb_service_add(dtb, dtb_size, DT_PORT, DTB_PORT, &dtb_ktipc_server); if (rc < 0) { panic("Failed (%d) to add dtb service to server\n", rc); } } LK_INIT_HOOK(platform_dtb, platform_dtb_init, LK_INIT_LEVEL_THREADING + 1);