1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "boot-shim.h" 6#include "debug.h" 7#include "devicetree.h" 8#include "util.h" 9 10#include <ddk/protocol/platform-defs.h> 11#include <libzbi/zbi.h> 12#include <limits.h> 13#include <stdbool.h> 14#include <stddef.h> 15#include <string.h> 16#include <zircon/boot/driver-config.h> 17 18// uncomment to dump device tree at boot 19// #define PRINT_DEVICE_TREE 20 21// Uncomment to list ZBI items. 22#ifndef PRINT_ZBI 23#define PRINT_ZBI 0 24#endif 25 26// used in boot-shim-config.h and in this file below 27static void append_boot_item(zbi_header_t* container, 28 uint32_t type, uint32_t extra, 29 const void* payload, uint32_t length) { 30 zbi_result_t result = zbi_append_section( 31 container, SIZE_MAX, length, type, extra, 0, payload); 32 if (result != ZBI_RESULT_OK) { 33 fail("zbi_append_section failed\n"); 34 } 35} 36 37// defined in boot-shim-config.h 38static void append_board_boot_item(zbi_header_t* container); 39 40#if USE_DEVICE_TREE_CPU_COUNT 41static void set_cpu_count(uint32_t cpu_count); 42#endif 43 44// Include board specific definitions 45#include "boot-shim-config.h" 46 47#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1)) 48 49#if HAS_DEVICE_TREE 50typedef enum { 51 NODE_NONE, 52 NODE_CHOSEN, 53 NODE_MEMORY, 54 NODE_CPU, 55 NODE_INTC, 56} node_t; 57 58typedef struct { 59 node_t node; 60 uintptr_t initrd_start; 61 size_t memory_base; 62 size_t memory_size; 63 char* cmdline; 64 size_t cmdline_length; 65 uint32_t cpu_count; 66 int gic_version; 67} device_tree_context_t; 68 69static int node_callback(int depth, const char *name, void *cookie) { 70#ifdef PRINT_DEVICE_TREE 71 uart_puts("node: "); 72 uart_puts(name); 73 uart_puts("\n"); 74#endif 75 76 device_tree_context_t* ctx = cookie; 77 78 if (!strcmp(name, "chosen")) { 79 ctx->node = NODE_CHOSEN; 80 } else if (!strcmp(name, "memory") || !strcmp(name, "memory@00000000")) { 81 ctx->node = NODE_MEMORY; 82 } else if (!strncmp(name, "cpu@", 4)) { 83 ctx->node = NODE_CPU; 84 ctx->cpu_count++; 85 } else if (!strcmp(name, "intc")) { 86 ctx->node = NODE_INTC; 87 } else { 88 ctx->node = NODE_NONE; 89 } 90 91 return 0; 92} 93 94static int prop_callback(const char *name, uint8_t *data, uint32_t size, void *cookie) { 95#ifdef PRINT_DEVICE_TREE 96 uart_puts(" prop: "); 97 uart_puts(name); 98 uart_puts(" size: "); 99 uart_print_hex(size); 100#endif 101 102 device_tree_context_t* ctx = cookie; 103 104 switch (ctx->node) { 105 case NODE_CHOSEN: 106 if (!strcmp(name, "linux,initrd-start")) { 107 if (size == sizeof(uint32_t)) { 108 ctx->initrd_start = dt_rd32(data); 109 } else if (size == sizeof(uint64_t)) { 110 uint64_t most = dt_rd32(data); 111 uint64_t least = dt_rd32(data + 4); 112 ctx->initrd_start = (most << 32) | least; 113 } else { 114 fail("bad size for linux,initrd-start in device tree\n"); 115 } 116 } else if (!strcmp(name, "bootargs")) { 117 ctx->cmdline = (char *)data; 118 ctx->cmdline_length = size; 119 } 120 break; 121 case NODE_MEMORY: 122 if (!strcmp(name, "reg") && size == 16) { 123 // memory size is big endian uint64_t at offset 0 124 uint64_t most = dt_rd32(data + 0); 125 uint64_t least = dt_rd32(data + 4); 126 ctx->memory_base = (most << 32) | least; 127 // memory size is big endian uint64_t at offset 8 128 most = dt_rd32(data + 8); 129 least = dt_rd32(data + 12); 130 ctx->memory_size = (most << 32) | least; 131 } 132 break; 133 case NODE_INTC: 134 if (!strcmp(name, "compatible")) { 135 if (!strncmp((const char *)data, "arm,gic-v3", size)) { 136 ctx->gic_version = 3; 137 } else if (!strncmp((const char *)data, "arm,cortex-a15-gic", size)) { 138 ctx->gic_version = 2; 139 } 140#ifdef PRINT_DEVICE_TREE 141 uart_puts(" gic version "); 142 uart_print_hex(ctx->gic_version); 143#endif 144 } 145 break; 146 default: 147 ; 148 } 149 150#ifdef PRINT_DEVICE_TREE 151 uart_puts("\n"); 152#endif 153 154 return 0; 155} 156 157// Parse the device tree to find our ZBI, kernel command line, and RAM size. 158static void* read_device_tree(void* device_tree, device_tree_context_t* ctx) { 159 ctx->node = NODE_NONE; 160 ctx->initrd_start = 0; 161 ctx->memory_base = 0; 162 ctx->memory_size = 0; 163 ctx->cmdline = NULL; 164 ctx->cpu_count = 0; 165 ctx->gic_version = -1; 166 167 devicetree_t dt; 168 dt.error = uart_puts; 169 int ret = dt_init(&dt, device_tree, 0xffffffff); 170 if (ret) { 171 fail("dt_init failed\n"); 172 } 173 dt_walk(&dt, node_callback, prop_callback, ctx); 174 175#if USE_DEVICE_TREE_CPU_COUNT 176 set_cpu_count(ctx->cpu_count); 177#endif 178#if USE_DEVICE_TREE_GIC_VERSION 179 set_gic_version(ctx->gic_version); 180#endif 181 182 // Use the device tree initrd as the ZBI. 183 return (void*)ctx->initrd_start; 184} 185 186static void append_from_device_tree(zbi_header_t* zbi, 187 device_tree_context_t* ctx) { 188 // look for optional RAM size in device tree 189 // do this last so device tree can override value in boot-shim-config.h 190 if (ctx->memory_size) { 191 zbi_mem_range_t mem_range; 192 mem_range.paddr = ctx->memory_base; 193 mem_range.length = ctx->memory_size; 194 mem_range.type = ZBI_MEM_RANGE_RAM; 195 196 uart_puts("Setting RAM base and size device tree value: "); 197 uart_print_hex(ctx->memory_base); 198 uart_puts(" "); 199 uart_print_hex(ctx->memory_size); 200 uart_puts("\n"); 201 append_boot_item(zbi, ZBI_TYPE_MEM_CONFIG, 0, 202 &mem_range, sizeof(mem_range)); 203 } else { 204 uart_puts("RAM size not found in device tree\n"); 205 } 206 207 // append kernel command line 208 if (ctx->cmdline && ctx->cmdline_length) { 209 append_boot_item(zbi, ZBI_TYPE_CMDLINE, 0, 210 ctx->cmdline, ctx->cmdline_length); 211 } 212} 213 214#else 215 216typedef struct {} device_tree_context_t; 217static void* read_device_tree(void* device_tree, device_tree_context_t* ctx) { 218 return NULL; 219} 220static void append_from_device_tree(zbi_header_t* zbi, 221 device_tree_context_t* ctx) { 222} 223 224#endif // HAS_DEVICE_TREE 225 226static void dump_words(const char* what, const void* data) { 227 uart_puts(what); 228 const uint64_t* words = data; 229 for (int i = 0; i < 8; ++i) { 230 uart_puts(i == 4 ? "\n " : " "); 231 uart_print_hex(words[i]); 232 } 233 uart_puts("\n"); 234} 235 236static zbi_result_t list_zbi_cb(zbi_header_t* item, void* payload, void* ctx) { 237 uart_print_hex((uintptr_t)item); 238 uart_puts(": length=0x"); 239 uart_print_hex(item->length); 240 uart_puts(" type=0x"); 241 uart_print_hex(item->type); 242 uart_puts(" extra=0x"); 243 uart_print_hex(item->extra); 244 uart_puts("\n"); 245 return ZBI_RESULT_OK; 246} 247 248static void list_zbi(zbi_header_t* zbi) { 249 uart_puts("ZBI container length 0x"); 250 uart_print_hex(zbi->length); 251 uart_puts("\n"); 252 zbi_for_each(zbi, &list_zbi_cb, NULL); 253 uart_puts("ZBI container ends 0x"); 254 uart_print_hex((uintptr_t)(zbi + 1) + zbi->length); 255 uart_puts("\n"); 256} 257 258boot_shim_return_t boot_shim(void* device_tree) { 259 uart_puts("boot_shim: hi there!\n"); 260 261 zircon_kernel_t* kernel = NULL; 262 263 // Check the ZBI from device tree. 264 device_tree_context_t ctx; 265 zbi_header_t* zbi = read_device_tree(device_tree, &ctx); 266 if (zbi != NULL) { 267 zbi_header_t* bad_hdr; 268 zbi_result_t check = zbi_check(zbi, &bad_hdr); 269 if (check == ZBI_RESULT_OK && zbi->length > sizeof(zbi_header_t) && 270 zbi[1].type == ZBI_TYPE_KERNEL_ARM64) { 271 kernel = (zircon_kernel_t*) zbi; 272 } else { 273 // No valid ZBI in device tree. 274 // We will look in embedded_zbi instead. 275 zbi = NULL; 276 } 277 } 278 279 // If there is a complete ZBI from device tree, ignore whatever might 280 // have been appended to the shim image. If not, the kernel is appended. 281 if (kernel == NULL) { 282 zbi_header_t* bad_hdr; 283 zbi_result_t check = zbi_check(&embedded_zbi, &bad_hdr); 284 if (check != ZBI_RESULT_OK) { 285 fail("no ZBI from device tree and no valid ZBI embedded\n"); 286 } 287 if (embedded_zbi.hdr_file.length > sizeof(zbi_header_t) && 288 embedded_zbi.hdr_kernel.type == ZBI_TYPE_KERNEL_ARM64) { 289 kernel = &embedded_zbi; 290 } else { 291 fail("no ARM64 kernel in ZBI from device tree or embedded ZBI\n"); 292 } 293 } 294 295 // If there was no ZBI at all from device tree then use the embedded ZBI 296 // along with the embedded kernel. Otherwise always use the ZBI from 297 // device tree, whether the kernel is in that ZBI or was embedded. 298 if (zbi == NULL) { 299 zbi = &kernel->hdr_file; 300 } 301 302 // Add board-specific ZBI items. 303 append_board_boot_item(zbi); 304 305 // Append items from device tree. 306 append_from_device_tree(zbi, &ctx); 307 308 uint8_t* const kernel_end = 309 (uint8_t*)&kernel->data_kernel + 310 kernel->hdr_kernel.length + 311 kernel->data_kernel.reserve_memory_size; 312 313 uart_puts("Kernel at "); 314 uart_print_hex((uintptr_t)kernel); 315 uart_puts(" to "); 316 uart_print_hex((uintptr_t)kernel_end); 317 uart_puts(" reserved "); 318 uart_print_hex(kernel->data_kernel.reserve_memory_size); 319 uart_puts("\nZBI at "); 320 uart_print_hex((uintptr_t)zbi); 321 uart_puts(" to "); 322 uart_print_hex((uintptr_t)(zbi + 1) + zbi->length); 323 uart_puts("\n"); 324 325 if ((uint8_t*)zbi < kernel_end && zbi != &kernel->hdr_file) { 326 fail("expected kernel to be loaded lower in memory than initrd\n"); 327 } 328 329 if (PRINT_ZBI) { 330 list_zbi(zbi); 331 } 332 333 if (zbi == &kernel->hdr_file || (uintptr_t)zbi % 4096 != 0) { 334 // The ZBI needs to be page-aligned, so move it up. 335 // If it's a complete ZBI, splice out the kernel and move it higher. 336 zbi_header_t* old = zbi; 337 zbi = (void*)(((uintptr_t)old + 4095) & -(uintptr_t)4096); 338 if (old == &kernel->hdr_file) { 339 // Length of the kernel item payload, without header. 340 uint32_t kernel_len = kernel->hdr_kernel.length; 341 342 // Length of the ZBI container, including header, without kernel. 343 uint32_t zbi_len = kernel->hdr_file.length - kernel_len; 344 345 uart_puts("Splitting kernel "); 346 uart_print_hex(kernel_len); 347 uart_puts(" from ZBI "); 348 uart_print_hex(zbi_len); 349 350 // First move the kernel up out of the way. 351 uintptr_t zbi_end = (uintptr_t)(old + 1) + old->length; 352 if (zbi_end < (uintptr_t)zbi + zbi_len) { 353 zbi_end = (uintptr_t)zbi + zbi_len; 354 } 355 kernel = (void*)((zbi_end + KERNEL_ALIGN - 1) & 356 -(uintptr_t)KERNEL_ALIGN); 357 uart_puts("\nKernel to "); 358 uart_print_hex((uintptr_t)kernel); 359 memcpy(kernel, old, (2 * sizeof(*zbi)) + kernel_len); 360 // Fix up the kernel's solo container size. 361 kernel->hdr_file.length = sizeof(*zbi) + kernel_len; 362 363 // Now move the ZBI into its aligned place and fix up the 364 // container header to exclude the kernel. 365 uart_puts(" ZBI to "); 366 uart_print_hex((uintptr_t)zbi); 367 zbi_header_t header = *old; 368 header.length -= kernel->hdr_file.length; 369 void* payload = (uint8_t*)(old + 1) + kernel->hdr_file.length; 370 memmove(zbi + 1, payload, header.length); 371 *zbi = header; 372 373 uart_puts("\nKernel container length "); 374 uart_print_hex(kernel->hdr_file.length); 375 uart_puts(" ZBI container length "); 376 uart_print_hex(zbi->length); 377 uart_puts("\n"); 378 } else { 379 uart_puts("Relocating whole ZBI for alignment\n"); 380 memmove(zbi, old, sizeof(*old) + old->length); 381 } 382 } 383 384 if ((uintptr_t)kernel % KERNEL_ALIGN != 0) { 385 // The kernel has to be relocated for alignment. 386 uart_puts("Relocating kernel for alignment\n"); 387 zbi_header_t* old = &kernel->hdr_file; 388 kernel = (void*)(((uintptr_t)(zbi + 1) + zbi->length + 389 KERNEL_ALIGN - 1) & -(uintptr_t)KERNEL_ALIGN); 390 memmove(kernel, old, sizeof(*old) + old->length); 391 } 392 393 boot_shim_return_t result = { 394 .entry = (uintptr_t)kernel + kernel->data_kernel.entry, 395 .zbi = zbi, 396 }; 397 uart_puts("Entering kernel at "); 398 uart_print_hex(result.entry); 399 uart_puts(" with ZBI "); 400 uart_print_hex((uintptr_t)result.zbi); 401 uart_puts("\n"); 402 return result; 403} 404