diff --git a/ast27x0/Makefile b/ast27x0/Makefile index 4cae78d..cf201f0 100644 --- a/ast27x0/Makefile +++ b/ast27x0/Makefile @@ -39,24 +39,29 @@ GIT_VERSION := git-$(shell git rev-parse --short HEAD) # Without these flags, function pointers in .data may be NULL or invalid at # runtime. CFLAGS = -Os -Wall -Wextra -g -mcpu=cortex-a35 -fno-stack-protector \ - -no-pie -fno-pic \ - -I ./include -I ../lib/libfdt -I ../lib/libc/minimal/include + -no-pie -fno-pic \ + -I ./include -I ../lib/libfdt -I ../lib/libc/minimal/include + CFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\" ASFLAGS = $(CFLAGS) -Wa,-mcpu=cortex-a35 LDSCRIPT = bootrom.ld MAPFILE = bootrom.map LDFLAGS = -Wl,--build-id=none -static -nostdlib -T $(LDSCRIPT) -Wl,-Map=$(MAPFILE) -OBJS := start.o image.o uart_aspeed.o uart_console.o ssp_tsp.o \ - ../lib/libc/minimal/source/string/string.o \ - ../lib/libfdt/fdt.o ../lib/libfdt/fdt_ro.o +OBJS := start.o image.o stor.o ast_loader.o fmc_image.o board_ast2700.o \ + manifest.o manifest_image.o \ + uart_aspeed.o uart_console.o ssp_tsp.o \ + ../lib/libc/minimal/source/string/string.o \ + ../lib/libfdt/fdt.o ../lib/libfdt/fdt_ro.o \ + ../lib/libfdt/fdt_rw.o ../lib/libfdt/fdt_wip.o \ + ../lib/libfdt/fdt_addresses.o .PHONY: all clean all: ast27x0_bootrom.bin ast27x0_bootrom.asm clean: rm -f *.o *.bin *.elf *.asm *.map ../lib/libfdt/*.o \ - ../lib/libc/minimal/source/string/*.o + ../lib/libc/minimal/source/string/*.o ast27x0_bootrom.bin: ast27x0_bootrom.elf $(OBJCOPY) -O binary $< $@ diff --git a/ast27x0/ast_loader.c b/ast27x0/ast_loader.c new file mode 100644 index 0000000..1caa972 --- /dev/null +++ b/ast27x0/ast_loader.c @@ -0,0 +1,87 @@ +/* + * Firmware image loader helpers. + * + * Copyright (C) 2026 ASPEED Technology Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#define POLY 0xEDB88320 /* reflection of 0x04C11DB7 */ +#define INITIAL_CRC 0xFFFFFFFF +#define FINAL_XOR 0xFFFFFFFF + +static uint32_t crc_table[256]; + +void generate_crc32_table(void) +{ + uint32_t crc; + + for (uint32_t i = 0; i < 256; i++) { + crc = i; + + for (int j = 0; j < 8; j++) { + crc = (crc & 1) ? (crc >> 1) ^ POLY : (crc >> 1); + } + + crc_table[i] = crc; + } +} + +uint32_t calc_checksum(const uint8_t *data, size_t length) +{ + uint32_t crc = INITIAL_CRC; + + for (size_t i = 0; i < length; i++) { + crc = (crc >> 8) ^ crc_table[(crc ^ data[i]) & 0xFF]; + } + + return crc ^ FINAL_XOR; +} + +int ast_loader_read(uint64_t *dst, uint64_t src, uint32_t len) +{ + uprintf("%s: dst=0x%lx, src=0x%lx, len=%d\n", + __func__, dst, src, len); + memcpy(dst, (void *)(uintptr_t)src, len); + + return CPTRA_SUCCESS; +} + +int _ast_loader_load_image(uint32_t type, uint32_t *dst) +{ + const struct image_info *img_info = stor_get_image_info_table(); + uint32_t sz = 0; + + uprintf("%s: %s, type=%d, dst=0x%lx\n", __func__, + cptra_ime_get_image_name(img_info[type].id), type, dst); + stor_load(type, dst, &sz); + + return CPTRA_SUCCESS; +} + +int ast_loader_load_image(uint32_t type, uint32_t *dst) +{ + return _ast_loader_load_image(type, dst); +} + +int ast_loader_load_manifest_image(uint32_t type, uint32_t *dst) +{ + return _ast_loader_load_image(type, dst); +} + diff --git a/ast27x0/board_ast2700.c b/ast27x0/board_ast2700.c new file mode 100644 index 0000000..d1f626e --- /dev/null +++ b/ast27x0/board_ast2700.c @@ -0,0 +1,236 @@ +/* + * Caliptra manifest boot image loader. + * + * Copyright (C) 2026 ASPEED Technology Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PSP_TIMEOUT 100000000ULL +#define MANIFEST_SEARCH_START (ASPEED_FMC_CS0_BASE) +#define MANIFEST_SEARCH_END (MANIFEST_SEARCH_START + 0x400000) +#define MANIFEST_SEARCH_STEP 0x10000 + +static struct reserved_mem_info reservedinfo = { + .ssp = { .addr = 0x42c000000ULL, .size = 0x02000000ULL }, + .tsp = { .addr = 0x42e000000ULL, .size = 0x02000000ULL }, + .atf = { .addr = 0x430000000ULL, .size = 0x00080000ULL }, + .tee = { .addr = 0x430080000ULL, .size = 0x01000000ULL }, + .ipc_ssp = { .addr = 0x431080000ULL, .size = 0x00800000ULL } +}; + +static bool has_pspfw; +static bool has_sspfw; +static bool has_tspfw; + +extern void panic(const char *); + +void board_manifest_image_post_process(uint32_t fw_id) +{ + uintptr_t ep = cptra_ime_get_load_addr(fw_id); + uint64_t ep_arm = 0; + + /* convert to Arm view */ + ep_arm = convert_mcu_addr_to_arm_dram((uint64_t)ep); + + switch (fw_id) { + case CPTRA_SSP_FW_ID: + ssp_init(ep_arm, &reservedinfo); + has_sspfw = true; + break; + case CPTRA_ATF_FW_ID: + has_pspfw = true; + writel(ep_arm >> 4, SCU0_CA35_RVBAR0); + writel(ep_arm >> 4, SCU0_CA35_RVBAR1); + writel(ep_arm >> 4, SCU0_CA35_RVBAR2); + writel(ep_arm >> 4, SCU0_CA35_RVBAR3); + break; + case CPTRA_UBOOT_FW_ID: + writel((uint32_t)ep_arm, SCU0_CPU_SMP_EP0); + writel((uint32_t)(ep_arm >> 32), SCU0_CPU_SMP_EP0 + 4); + break; + case CPTRA_TSP_FW_ID: + tsp_init(ep_arm, &reservedinfo); + has_tspfw = true; + break; + default: + break; + } +} + +static void board_prepare_for_boot(void) +{ + if (has_pspfw) { + /* clean up secondary entries */ + writel(0x0, SCU0_CPU_SMP_EP1); + writel(0x0, SCU0_CPU_SMP_EP1 + 4); + writel(0x0, SCU0_CPU_SMP_EP2); + writel(0x0, SCU0_CPU_SMP_EP2 + 4); + writel(0x0, SCU0_CPU_SMP_EP3); + writel(0x0, SCU0_CPU_SMP_EP3 + 4); + + /* release CA35 reset */ + writel(0x1, SCU0_CA35_REL); + } + + /* release SSP reset */ + if (has_sspfw) { + ssp_enable(); + } + + /* release TSP reset */ + if (has_tspfw) { + tsp_enable(); + } +} + +static int find_manifest_image(uint64_t start_addr, uint64_t end_addr, + uint64_t search_step, uint64_t *manifest_base) +{ + struct cptra_checksum_info *chk; + struct cptra_manifest_hdr *hdr; + uint32_t hdr_crc32 = 0; + uint32_t hdr_size; + uint32_t chk_size; + uint64_t addr; + + hdr_size = sizeof(struct cptra_manifest_hdr); + chk_size = sizeof(struct cptra_checksum_info); + + for (addr = start_addr; + (addr + hdr_size + chk_size) <= end_addr; + addr += search_step) { + + hdr = (struct cptra_manifest_hdr *)addr; + chk = (struct cptra_checksum_info *)(addr + hdr_size); + + if (hdr->magic == CPTRA_FLASH_IMG_MAGIC && + hdr->img_count < CPTRA_IMC_ENTRY_COUNT) { + /* Check the flash image header crc checksum */ + generate_crc32_table(); + hdr_crc32 = calc_checksum((uint8_t *)hdr, hdr_size); + if (hdr_crc32 == chk->hdr_checksum) { + uprintf("Found valid caliptra flash image at 0x%lx\n", addr); + *manifest_base = addr; + return CPTRA_SUCCESS; + } + } + } + + uprintf("No valid caliptra flash image found in range"); + uprintf(" 0x%lx - 0x%lx (step: 0x%lx)\n", + start_addr, end_addr, search_step); + + return CPTRA_ERR_IMAGE_OFFSET_INVALID; +} + +static void dump_reserved_memory(struct reserved_mem_info *info) +{ + struct { + const char *path; + struct mem_region *region; + } nodes[] = { + { SSP_MEMORY_NODE, &info->ssp }, + { TSP_MEMORY_NODE, &info->tsp }, + { ATF_MEMORY_NODE, &info->atf }, + { OPTEE_MEMORY_NODE, &info->tee }, + { IPC_SSP_MEMORY_NODE, &info->ipc_ssp }, + }; + size_t i; + + for (i = 0; i < ARRAY_SIZE(nodes); i++) { + uprintf("[reserved] %s base: 0x%lx size: 0x%lx\n", nodes[i].path, + nodes[i].region->addr, nodes[i].region->size); + } +} + +int load_manifest_boot_image(uint64_t *jump_addr) +{ + const struct image_info *img_info = stor_get_image_info_table(); + struct cptra_image_context *cptra_ctx = cptra_get_ctx(); + uint64_t timeout = PSP_TIMEOUT; + uint64_t manifest_base = 0; + uint64_t uboot_start_addr; + uint64_t uboot_end_addr; + int ret = CPTRA_SUCCESS; + void *dtb_ptr = NULL; + + /* Find manifest image */ + ret = find_manifest_image(MANIFEST_SEARCH_START, MANIFEST_SEARCH_END, + MANIFEST_SEARCH_STEP, &manifest_base); + if (ret != CPTRA_SUCCESS) { + return ret; + } + + cptra_ctx->manifest_base = manifest_base; + + ret = stor_init(); + if (ret != CPTRA_SUCCESS) { + return ret; + } + + if (img_info[CPTRA_UBOOT_FW_ID].size > 0) { + uboot_start_addr = img_info[CPTRA_UBOOT_FW_ID].offset; + uboot_end_addr = uboot_start_addr + img_info[CPTRA_UBOOT_FW_ID].size; + /* Try to find and load a valid U-Boot DTB */ + dtb_ptr = find_and_load_appended_dtb(uboot_start_addr, uboot_end_addr); + if (dtb_ptr) { + get_reserved_memory(dtb_ptr, &reservedinfo); + } + } else { + uprintf("[reserved]: No U-Boot image found in caliptra flash image.\n"); + uprintf("[reserved]: Using default reserved memory layout.\n"); + dump_reserved_memory(&reservedinfo); + } + + ret = cptra_verify_abb_loader(); + if (ret != CPTRA_SUCCESS) { + return ret; + } + + ret = cptra_load_abb_image(); + if (ret != CPTRA_SUCCESS) { + return ret; + } + + board_prepare_for_boot(); + + uprintf("Waiting release PSP ...\n"); + + while (!(readl(SCU0_CA35_REL) & BIT(0))) { + if (--timeout == 0) { + uprintf("ERROR: PSP release timeout!\n"); + panic(""); + } + } + + uprintf("PSP is released ...\n"); + + *jump_addr = (uint64_t)readl(SCU0_CA35_RVBAR0) << 4; + uprintf("\nJumping to BL31 (Trusted Firmware-A) at 0x%lx\n\n", *jump_addr); + + return ret; +} + diff --git a/ast27x0/bootrom.ld b/ast27x0/bootrom.ld index 92e65f4..96a2591 100644 --- a/ast27x0/bootrom.ld +++ b/ast27x0/bootrom.ld @@ -19,50 +19,50 @@ MEMORY { - rom (rx) : ORIGIN = 0x00000000, LENGTH = 128K - ram (arwx) : ORIGIN = 0x10000000, LENGTH = 128K + rom (rx) : ORIGIN = 0x00000000, LENGTH = 128K + ram (arwx) : ORIGIN = 0x10000000, LENGTH = 128K } SECTIONS { - /* Vectors are loaded into ROM */ - .text.vectors : { - __vectors_vma = .; - *(.text.vectors) - . = 0x100; - __vectors_end = .; - } >rom - /* The rest of the code follows the vectors. - * The main code and read-only data, located in ROM - */ - .text : { - __text = .; - *(.text .text.*) - . = ALIGN(32); - *(.rodata .rodata.*) - . = ALIGN(32); - __etext = .; - } >rom - /* - * Initialized data section - * Data follows the code in ROM, and is copied in RAM. - */ - .data : { - __data = .; - *(.data .data.*) - . = ALIGN(32); - __edata = .; - } >ram AT>rom - __data_loadaddr = LOADADDR(.data); + /* Vectors are loaded into ROM */ + .text.vectors : { + __vectors_vma = .; + *(.text.vectors) + . = 0x100; + __vectors_end = .; + } >rom + /* The rest of the code follows the vectors. + * The main code and read-only data, located in ROM + */ + .text : { + __text = .; + *(.text .text.*) + . = ALIGN(32); + *(.rodata .rodata.*) + . = ALIGN(32); + __etext = .; + } >rom + /* + * Initialized data section + * Data follows the code in ROM, and is copied in RAM. + */ + .data : { + __data = .; + *(.data .data.*) + . = ALIGN(32); + __edata = .; + } >ram AT>rom + __data_loadaddr = LOADADDR(.data); - /* Zero-initialized data (BSS) lives in RAM, after the data section. */ - .bss : { - __bss_start = .; - *(.bss .bss.*) - . = ALIGN(32); - *(COMMON) - . = ALIGN(32); - __bss_end = .; - __end = .; - } >ram + /* Zero-initialized data (BSS) lives in RAM, after the data section. */ + .bss : { + __bss_start = .; + *(.bss .bss.*) + . = ALIGN(32); + *(COMMON) + . = ALIGN(32); + __bss_end = .; + __end = .; + } >ram } diff --git a/ast27x0/fmc_image.c b/ast27x0/fmc_image.c new file mode 100644 index 0000000..d495f3a --- /dev/null +++ b/ast27x0/fmc_image.c @@ -0,0 +1,433 @@ +/* + * SoC First Mutable Code (FMC) and Flattened Image Tree (FIT) + * image parsing and loading. + * + * Copyright 2025 Google LLC + * Copyright (C) ASPEED Technology Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG 0 + +#define FIT_SEARCH_START (ASPEED_FMC_CS0_BASE) +#define FIT_SEARCH_END (FIT_SEARCH_START + 0x400000) +#define FIT_SEARCH_STEP 0x10000 + +extern void panic(const char *); + +static bool has_sspfw; +static bool has_tspfw; + +static uint64_t read_fit_address(const void *fdt, int node, + const char *prop_name) +{ + const char *node_name; + const fdt32_t *prop; + uint32_t addr_upper; + uint32_t addr_lower; + int len; + + if (!prop_name) { + uprintf("Invalid: prop_name is NULL!\n"); + return 0; + } + + node_name = fdt_get_name(fdt, node, NULL); + if (!node_name) { + node_name = ""; + } + + prop = fdt_getprop(fdt, node, prop_name, &len); + if (!prop) { + uprintf("[%s] %s: property not found\n", node_name, prop_name); + return 0; + } + + if (len == 4) { + return (uint64_t)fdt32_to_cpu(prop[0]); + } else if (len == 8) { + addr_upper = fdt32_to_cpu(prop[0]); + addr_lower = fdt32_to_cpu(prop[1]); + return ((uint64_t)addr_upper << 32) | addr_lower; + } else { + uprintf("[%s] %s: invalid length (%d bytes, expected 4 or 8)\n", + node_name, prop_name, len); + return 0; + } +} + +#if DEBUG +static void dump_fit_image(const void *fit_blob) +{ + uintptr_t data_offset; + int images_offset; + const void *data; + int node_offset; + const char *str; + uint64_t addr; + int data_len; + + images_offset = fdt_path_offset(fit_blob, "/images"); + if (images_offset < 0) { + uprintf("No /images node found\n"); + return; + } + + fdt_for_each_subnode(node_offset, fit_blob, images_offset) { + str = fdt_get_name(fit_blob, node_offset, NULL); + uprintf("Image node: %s\n", str); + + str = fdt_getprop(fit_blob, node_offset, "description", NULL); + if (str) { + uprintf(" description: %s\n", str); + } + + addr = read_fit_address(fit_blob, node_offset, "load"); + if (addr) { + uprintf(" load address: 0x%016llx\n", (unsigned long long)addr); + } + + addr = read_fit_address(fit_blob, node_offset, "entry"); + if (addr) { + uprintf(" entry point: 0x%016llx\n", (unsigned long long)addr); + } + + str = fdt_getprop(fit_blob, node_offset, "type", NULL); + if (str) { + uprintf(" type: %s\n", str); + } + + str = fdt_getprop(fit_blob, node_offset, "os", NULL); + if (str) { + uprintf(" os: %s\n", str); + } + + str = fdt_getprop(fit_blob, node_offset, "arch", NULL); + if (str) { + uprintf(" arch: %s\n", str); + } + + str = fdt_getprop(fit_blob, node_offset, "compression", NULL); + if (str) { + uprintf(" compression: %s\n", str); + } + + data = fdt_getprop(fit_blob, node_offset, "data", &data_len); + if (data && data_len > 0) { + data_offset = (uintptr_t)data - (uintptr_t)fit_blob; + uprintf(" data: %d bytes @ offset 0x%lx\n", + data_len, data_offset); + } else { + uprintf(" data: not found or empty\n"); + } + } +} +#endif + +/* + * Loads the "U-Boot" image from the FIT and returns its end address in memory. + * + * This function must be called before loading other images because some images, + * such as "fdt", may not have an explicit "load" property defined. In those + * cases, their load address is determined by placing them immediately after the + * u-boot image in memory. + * + * Loading U-Boot first ensures a well-defined memory layout baseline for + * subsequent images that rely on relative placement. + */ +static uint64_t load_uboot_image(const void *fit_blob) +{ + uintptr_t data_offset; + uint64_t load_addr; + uint64_t dram_addr; + int images_offset; + const void *data; + const char *name; + int node_offset; + int data_len; + + images_offset = fdt_path_offset(fit_blob, "/images"); + if (images_offset < 0) { + uprintf("No /images node found\n"); + return 0; + } + + fdt_for_each_subnode(node_offset, fit_blob, images_offset) { + name = fdt_get_name(fit_blob, node_offset, NULL); + if (strcmp(name, "uboot") != 0) { + continue; + } + + load_addr = read_fit_address(fit_blob, node_offset, "load"); + if (!load_addr) { + uprintf("[%s] has no load address!\n", name); + return 0; + } + + uprintf("[%s] load address: 0x%lx\n", name, + (unsigned long long)load_addr); + + data = fdt_getprop(fit_blob, node_offset, "data", &data_len); + if (!data || data_len <= 0) { + uprintf("[%s] has no data!\n", name); + return 0; + } + + data_offset = (uintptr_t)data - (uintptr_t)fit_blob; + uprintf("[%s] load end address: 0x%lx\n", name, + (unsigned long long)(load_addr + data_len)); + uprintf("[%s] data: %d bytes @ offset 0x%lx\n", name, data_len, + data_offset); + dram_addr = convert_mcu_addr_to_arm_dram(load_addr); + uprintf("[%s] loading %d bytes to 0x%lx ... ", name, data_len, + (unsigned long long)dram_addr); + memcpy((void *)(uintptr_t)dram_addr, data, data_len); + uprintf("done\n"); + return load_addr + data_len; + } + + uprintf("[uboot] not found in FIT\n"); + return 0; +} + +/* + * Loads all images from the FIT except "U-Boot". + * + * If an image has a "load" property, its value is remapped to the 64-bit DRAM + * address space and used directly. If the image is "fdt" and does not have a + * "load" property, it is placed immediately after the U-Boot image, using the + * given uboot_end address as its load location. + * + * This function depends on uboot_end being correctly computed in advance by + * load_uboot_image(). This ensures a clean and predictable memory layout even + * if some images do not define explicit load addresses in the FIT. + */ +static void load_other_fit_images(const void *fit_blob, uint64_t uboot_end, + uint64_t *dest_addr, + const struct reserved_mem_info *info) +{ + uintptr_t data_offset; + uint64_t load_addr; + uint64_t dram_addr; + int images_offset; + const void *data; + const char *name; + int node_offset; + int data_len; + + images_offset = fdt_path_offset(fit_blob, "/images"); + if (images_offset < 0) { + uprintf("No /images node found\n"); + return; + } + + fdt_for_each_subnode(node_offset, fit_blob, images_offset) { + name = fdt_get_name(fit_blob, node_offset, NULL); + + /* Skip U-Boot, which should already be loaded */ + if (strcmp(name, "uboot") == 0) { + continue; + } + + data = fdt_getprop(fit_blob, node_offset, "data", &data_len); + if (!data || data_len <= 0) { + uprintf("[%s] skip: no data\n", name); + continue; + } + + load_addr = read_fit_address(fit_blob, node_offset, "load"); + + if (load_addr) { + uprintf("[%s] load address: 0x%lx\n", name, + (unsigned long long)load_addr); + /* Image has explicit load address, remap for ARM DRAM view */ + dram_addr = convert_mcu_addr_to_arm_dram(load_addr); + /* The next image to jump to is BL31 (Trusted Firmware-A) */ + if (strcmp(name, "atf") == 0) { + *dest_addr = dram_addr; + } + + /* Init co-processor */ + if (strcmp(name, "sspfw") == 0) { + ssp_init(dram_addr, info); + has_sspfw = true; + } + + if (strcmp(name, "tspfw") == 0) { + tsp_init(dram_addr, info); + has_tspfw = true; + } + } else if (strcmp(name, "fdt") == 0 && uboot_end) { + /* fdt has no load address, fallback to uboot_end */ + load_addr = uboot_end; + dram_addr = convert_mcu_addr_to_arm_dram(load_addr); + uprintf("[%s] no load addr, fallback to u-boot end: 0x%lx\n", + name, (unsigned long long)load_addr); + } else { + uprintf("[%s] skip: no load address and no fallback\n", name); + continue; + } + + data_offset = (uintptr_t)data - (uintptr_t)fit_blob; + uprintf("[%s] data: %d bytes @ offset 0x%lx\n", + name, data_len, data_offset); + uprintf("[%s] loading %d bytes to 0x%lx ... ", + name, data_len, (unsigned long long)dram_addr); + memcpy((void *)(uintptr_t)dram_addr, data, data_len); + uprintf("done\n"); + } +} + +static const void *find_fit_image(uint64_t start_addr, uint64_t end_addr, + uint64_t search_step) +{ + const void *ptr = NULL; + int total_size; + uint64_t addr; + + if (search_step == 0) { + uprintf("search_step cannot be zero.\n"); + return NULL; + } + + for (addr = start_addr; addr < end_addr; addr += search_step) { + ptr = (const void *)(uintptr_t)addr; + + if (fdt_check_header(ptr) == 0) { + total_size = fdt_totalsize(ptr); + uprintf("Found valid FIT image at 0x%lx (size: 0x%x bytes)\n", + addr, total_size); + return ptr; + } + } + + uprintf("No valid FIT image found in range 0x%lx - 0x%lx (step: 0x%lx)\n", + start_addr, end_addr, search_step); + + return NULL; +} + +static int find_fmc_image(uint64_t start_addr, uint64_t end_addr, + uint64_t search_step, struct fmc_img_info *info) +{ + struct ast_fmc_header *hdr; + uint32_t fmc_header_size; + uint32_t payload_size; + uint32_t total_size; + uint64_t addr; + + if (info == NULL) { + return 0; + } + + fmc_header_size = sizeof(struct ast_fmc_header); + + for (addr = start_addr; + addr + fmc_header_size <= end_addr; + addr += search_step) { + hdr = (struct ast_fmc_header *)addr; + + if (hdr->preamble.magic == FMC_HDR_MAGIC) { + payload_size = hdr->body.size; + total_size = fmc_header_size + payload_size; + + if (payload_size > 0 && (addr + total_size) <= end_addr) { + info->payload_start = addr + fmc_header_size; + info->payload_end = ALIGN_UP(addr + total_size, search_step); + uprintf("Found valid FMC v%d image at 0x%lx (size: 0x%x)", + hdr->preamble.version, addr, total_size); + uprintf(", next FIT search @ 0x%lx\n", info->payload_end); + return 1; + } + } + } + + uprintf("No valid FMC image found in range 0x%lx - 0x%lx (step: 0x%lx)\n", + start_addr, end_addr, search_step); + + return 0; +} + +uint64_t load_fit_boot_image(void) +{ + struct reserved_mem_info reservedinfo = {0}; + struct fmc_img_info fmcinfo = {0}; + uint64_t search_next_addr; + uint64_t bl31_addr = 0; + const void *fit_blob; + void *dtb_ptr = NULL; + uint64_t uboot_end; + + search_next_addr = FIT_SEARCH_START; + + /* Find FMC image */ + if (find_fmc_image(search_next_addr, FIT_SEARCH_END, FIT_SEARCH_STEP, + &fmcinfo)) { + search_next_addr = fmcinfo.payload_end; + + /* Try to find and load a valid SPL DTB between FMC and U-Boot FIT */ + dtb_ptr = find_and_load_appended_dtb(fmcinfo.payload_start, + fmcinfo.payload_end); + if (dtb_ptr) { + get_reserved_memory(dtb_ptr, &reservedinfo); + } + } + + /* Find U-Boot FIT imag */ + fit_blob = find_fit_image(search_next_addr, + FIT_SEARCH_END, + FIT_SEARCH_STEP); + if (!fit_blob) { + panic(""); + } + +#if DEBUG + dump_fit_image(fit_blob); +#endif + + uboot_end = load_uboot_image(fit_blob); + + if (!uboot_end) { + panic(""); + } + + load_other_fit_images(fit_blob, uboot_end, &bl31_addr, &reservedinfo); + + if (!bl31_addr) { + uprintf("Error: BL31 (Trusted Firmware-A) not found, halting.\n"); + panic(""); + } + + if (has_sspfw) { + ssp_enable(); + } + + if (has_tspfw) { + tsp_enable(); + } + + uprintf("\nJumping to BL31 (Trusted Firmware-A) at 0x%lx\n\n", + bl31_addr); + return bl31_addr; +} + diff --git a/ast27x0/image.c b/ast27x0/image.c index d00e792..76e2c73 100644 --- a/ast27x0/image.c +++ b/ast27x0/image.c @@ -23,18 +23,9 @@ #include #include #include -#include - -#define DEBUG 0 - -#define FIT_SEARCH_START (FMCCS0) -#define FIT_SEARCH_END (FMCCS0 + 0x400000) -#define FIT_SEARCH_STEP 0x10000 - -extern void panic(const char *); - -static bool has_sspfw; -static bool has_tspfw; +#include +#include +#include /* * This global struct is explicitly initialized, so it is placed in the .data @@ -79,7 +70,7 @@ static void print_build_info() * BootMCU loads the U-BOOT FIT image to a 32-bit address (e.g. 0x80000000), * but Cortex-A35 accesses DRAM starting at DRAM_ADDR (e.g. 0x400000000). */ -static inline uint64_t convert_mcu_addr_to_arm_dram(uint64_t mcu_load_addr) +uint64_t convert_mcu_addr_to_arm_dram(uint64_t mcu_load_addr) { /* * If address is below 0x80000000, it's a physical address in SRAM. @@ -89,347 +80,24 @@ static inline uint64_t convert_mcu_addr_to_arm_dram(uint64_t mcu_load_addr) return mcu_load_addr; } - return DRAM_ADDR + ((uint64_t)mcu_load_addr - 0x80000000); -} - -static uint64_t read_fit_address(const void *fdt, int node, - const char *prop_name) -{ - const char *node_name; - const fdt32_t *prop; - uint32_t addr_upper; - uint32_t addr_lower; - int len; - - if (!prop_name) { - uprintf("Invalid: prop_name is NULL!\n"); - return 0; - } - - node_name = fdt_get_name(fdt, node, NULL); - if (!node_name) { - node_name = ""; - } - - prop = fdt_getprop(fdt, node, prop_name, &len); - if (!prop) { - uprintf("[%s] %s: property not found\n", node_name, prop_name); - return 0; - } - - if (len == 4) { - return (uint64_t)fdt32_to_cpu(prop[0]); - } else if (len == 8) { - addr_upper = fdt32_to_cpu(prop[0]); - addr_lower = fdt32_to_cpu(prop[1]); - return ((uint64_t)addr_upper << 32) | addr_lower; - } else { - uprintf("[%s] %s: invalid length (%d bytes, expected 4 or 8)\n", - node_name, prop_name, len); - return 0; - } -} - -#if DEBUG -static void dump_fit_image(const void *fit_blob) -{ - uintptr_t data_offset; - int images_offset; - const void *data; - int node_offset; - const char *str; - uint64_t addr; - int data_len; - - images_offset = fdt_path_offset(fit_blob, "/images"); - if (images_offset < 0) { - uprintf("No /images node found\n"); - return; - } - - fdt_for_each_subnode(node_offset, fit_blob, images_offset) { - str = fdt_get_name(fit_blob, node_offset, NULL); - uprintf("Image node: %s\n", str); - - str = fdt_getprop(fit_blob, node_offset, "description", NULL); - if (str) { - uprintf(" description: %s\n", str); - } - - addr = read_fit_address(fit_blob, node_offset, "load"); - if (addr) { - uprintf(" load address: 0x%016llx\n", (unsigned long long)addr); - } - - addr = read_fit_address(fit_blob, node_offset, "entry"); - if (addr) { - uprintf(" entry point: 0x%016llx\n", (unsigned long long)addr); - } - - str = fdt_getprop(fit_blob, node_offset, "type", NULL); - if (str) { - uprintf(" type: %s\n", str); - } - - str = fdt_getprop(fit_blob, node_offset, "os", NULL); - if (str) { - uprintf(" os: %s\n", str); - } - - str = fdt_getprop(fit_blob, node_offset, "arch", NULL); - if (str) { - uprintf(" arch: %s\n", str); - } - - str = fdt_getprop(fit_blob, node_offset, "compression", NULL); - if (str) { - uprintf(" compression: %s\n", str); - } - - data = fdt_getprop(fit_blob, node_offset, "data", &data_len); - if (data && data_len > 0) { - data_offset = (uintptr_t)data - (uintptr_t)fit_blob; - uprintf(" data: %d bytes @ offset 0x%lx\n", - data_len, data_offset); - } else { - uprintf(" data: not found or empty\n"); - } - } -} -#endif - -/* - * Loads the "U-Boot" image from the FIT and returns its end address in memory. - * - * This function must be called before loading other images because some images, - * such as "fdt", may not have an explicit "load" property defined. In those - * cases, their load address is determined by placing them immediately after the - * u-boot image in memory. - * - * Loading U-Boot first ensures a well-defined memory layout baseline for - * subsequent images that rely on relative placement. - */ -static uint64_t load_uboot_image(const void *fit_blob) -{ - uintptr_t data_offset; - uint64_t load_addr; - uint64_t dram_addr; - int images_offset; - const void *data; - const char *name; - int node_offset; - int data_len; - - images_offset = fdt_path_offset(fit_blob, "/images"); - if (images_offset < 0) { - uprintf("No /images node found\n"); - return 0; - } - - fdt_for_each_subnode(node_offset, fit_blob, images_offset) { - name = fdt_get_name(fit_blob, node_offset, NULL); - if (strcmp(name, "uboot") != 0) { - continue; - } - - load_addr = read_fit_address(fit_blob, node_offset, "load"); - if (!load_addr) { - uprintf("[%s] has no load address!\n", name); - return 0; - } - - uprintf("[%s] load address: 0x%lx\n", name, - (unsigned long long)load_addr); - - data = fdt_getprop(fit_blob, node_offset, "data", &data_len); - if (!data || data_len <= 0) { - uprintf("[%s] has no data!\n", name); - return 0; - } - - data_offset = (uintptr_t)data - (uintptr_t)fit_blob; - uprintf("[%s] load end address: 0x%lx\n", name, - (unsigned long long)(load_addr + data_len)); - uprintf("[%s] data: %d bytes @ offset 0x%lx\n", name, data_len, - data_offset); - dram_addr = convert_mcu_addr_to_arm_dram(load_addr); - uprintf("[%s] loading %d bytes to 0x%lx ... ", name, data_len, - (unsigned long long)dram_addr); - memcpy((void *)(uintptr_t)dram_addr, data, data_len); - uprintf("done\n"); - return load_addr + data_len; - } - - uprintf("[uboot] not found in FIT\n"); - return 0; + return SYS_DRAM_BASE + ((uint64_t)mcu_load_addr - 0x80000000); } /* - * Loads all images from the FIT except "U-Boot". - * - * If an image has a "load" property, its value is remapped to the 64-bit DRAM - * address space and used directly. If the image is "fdt" and does not have a - * "load" property, it is placed immediately after the U-Boot image, using the - * given uboot_end address as its load location. + * Scan the image tail for an appended Device Tree Blob (DTB), + * copy it to DRAM, and return its DRAM address if valid. * - * This function depends on uboot_end being correctly computed in advance by - * load_uboot_image(). This ensures a clean and predictable memory layout even - * if some images do not define explicit load addresses in the FIT. + * This is used to locate SPL or U-Boot DTBs that are appended + * after their raw images. */ -static void load_other_fit_images(const void *fit_blob, uint64_t uboot_end, - uint64_t *dest_addr, - const struct reserved_mem_info *info) +void *find_and_load_appended_dtb(uint64_t start_addr, uint64_t end_addr) { - uintptr_t data_offset; - uint64_t load_addr; - uint64_t dram_addr; - int images_offset; - const void *data; - const char *name; - int node_offset; - int data_len; - - images_offset = fdt_path_offset(fit_blob, "/images"); - if (images_offset < 0) { - uprintf("No /images node found\n"); - return; - } - - fdt_for_each_subnode(node_offset, fit_blob, images_offset) { - name = fdt_get_name(fit_blob, node_offset, NULL); - - /* Skip U-Boot, which should already be loaded */ - if (strcmp(name, "uboot") == 0) { - continue; - } - - data = fdt_getprop(fit_blob, node_offset, "data", &data_len); - if (!data || data_len <= 0) { - uprintf("[%s] skip: no data\n", name); - continue; - } - - load_addr = read_fit_address(fit_blob, node_offset, "load"); - - if (load_addr) { - uprintf("[%s] load address: 0x%lx\n", name, - (unsigned long long)load_addr); - /* Image has explicit load address, remap for ARM DRAM view */ - dram_addr = convert_mcu_addr_to_arm_dram(load_addr); - /* The next image to jump to is BL31 (Trusted Firmware-A) */ - if (strcmp(name, "atf") == 0) { - *dest_addr = dram_addr; - } - - /* Init co-processor */ - if (strcmp(name, "sspfw") == 0) { - ssp_init(dram_addr, info); - has_sspfw = true; - } - - if (strcmp(name, "tspfw") == 0) { - tsp_init(dram_addr, info); - has_tspfw = true; - } - } else if (strcmp(name, "fdt") == 0 && uboot_end) { - /* fdt has no load address, fallback to uboot_end */ - load_addr = uboot_end; - dram_addr = convert_mcu_addr_to_arm_dram(load_addr); - uprintf("[%s] no load addr, fallback to u-boot end: 0x%lx\n", - name, (unsigned long long)load_addr); - } else { - uprintf("[%s] skip: no load address and no fallback\n", name); - continue; - } - - data_offset = (uintptr_t)data - (uintptr_t)fit_blob; - uprintf("[%s] data: %d bytes @ offset 0x%lx\n", - name, data_len, data_offset); - uprintf("[%s] loading %d bytes to 0x%lx ... ", - name, data_len, (unsigned long long)dram_addr); - memcpy((void *)(uintptr_t)dram_addr, data, data_len); - uprintf("done\n"); - } -} - -static const void *find_fit_image(uint64_t start_addr, uint64_t end_addr, - uint64_t search_step) -{ - const void *ptr = NULL; - int total_size; - uint64_t addr; - - if (search_step == 0) { - uprintf("search_step cannot be zero.\n"); - return NULL; - } - - for (addr = start_addr; addr < end_addr; addr += search_step) { - ptr = (const void *)(uintptr_t)addr; - - if (fdt_check_header(ptr) == 0) { - total_size = fdt_totalsize(ptr); - uprintf("Found valid FIT image at 0x%lx (size: 0x%x bytes)\n", - addr, total_size); - return ptr; - } - } - - uprintf("No valid FIT image found in range 0x%lx - 0x%lx (step: 0x%lx)\n", - start_addr, end_addr, search_step); - - return NULL; -} - -static int find_fmc_image(uint64_t start_addr, uint64_t end_addr, - uint64_t search_step, struct fmc_img_info *info) -{ - struct ast_fmc_header *hdr; - uint32_t fmc_header_size; - uint32_t payload_size; - uint32_t total_size; - uint64_t addr; - - if (info == NULL) { - return 0; - } - - fmc_header_size = sizeof(struct ast_fmc_header); - - for (addr = start_addr; - addr + fmc_header_size <= end_addr; - addr += search_step) { - hdr = (struct ast_fmc_header *)addr; - - if (hdr->preamble.magic == FMC_HDR_MAGIC) { - payload_size = hdr->body.size; - total_size = fmc_header_size + payload_size; - - if (payload_size > 0 && (addr + total_size) <= end_addr) { - info->payload_start = addr + fmc_header_size; - info->payload_end = ALIGN_UP(addr + total_size, search_step); - uprintf("Found valid FMC v%d image at 0x%lx (size: 0x%x)", - hdr->preamble.version, addr, total_size); - uprintf(", next FIT search @ 0x%lx\n", info->payload_end); - return 1; - } - } - } - - uprintf("No valid FMC image found in range 0x%lx - 0x%lx (step: 0x%lx)\n", - start_addr, end_addr, search_step); - - return 0; -} - -static void *load_dtb_after_fmc(uint64_t fmc_end, uint64_t end_addr) -{ - void *dram_dtb_addr = (void *)(uintptr_t)DRAM_ADDR; + void *dram_dtb_addr = (void *)(uintptr_t)SYS_DRAM_BASE; const uint32_t *magic_ptr; size_t copy_size; uint64_t addr; - for (addr = ALIGN_UP(fmc_end, 4); addr + 4 < end_addr; addr += 4) { + for (addr = ALIGN_UP(start_addr, 4); addr + 4 < end_addr; addr += 4) { /* Check for DTB magic number (aligned on 4-byte boundary) */ magic_ptr = (const uint32_t *)(uintptr_t)addr; if (*magic_ptr != cpu_to_fdt32(FDT_MAGIC)) { @@ -450,75 +118,49 @@ static void *load_dtb_after_fmc(uint64_t fmc_end, uint64_t end_addr) } } - uprintf("No valid DTB found between 0x%lx and 0x%lx\n", fmc_end, end_addr); + uprintf("No valid DTB found between 0x%lx and 0x%lx\n", + start_addr, end_addr); return NULL; } uint64_t load_boot_image(void) { - struct reserved_mem_info reservedinfo = {0}; - struct fmc_img_info fmcinfo = {0}; - uint64_t search_next_addr; - uint64_t bl31_addr = 0; - const void *fit_blob; - void *dtb_ptr = NULL; - uint64_t uboot_end; + int ret = CPTRA_SUCCESS; + uint64_t jump_addr; uart_aspeed_init(UART12); uart_console_register(&ucons); - print_build_info(); - search_next_addr = FIT_SEARCH_START; - - /* Find FMC image */ - if (find_fmc_image(search_next_addr, FIT_SEARCH_END, FIT_SEARCH_STEP, - &fmcinfo)) { - search_next_addr = fmcinfo.payload_end; - - /* Try to find and load a valid SPL DTB between FMC and U-Boot FIT */ - dtb_ptr = load_dtb_after_fmc(fmcinfo.payload_start, - fmcinfo.payload_end); - if (dtb_ptr) { - get_reserved_memory(dtb_ptr, &reservedinfo); - } - } - - /* Find U-Boot FIT imag */ - fit_blob = find_fit_image(search_next_addr, - FIT_SEARCH_END, - FIT_SEARCH_STEP); - if (!fit_blob) { - panic(""); - } - -#if DEBUG - dump_fit_image(fit_blob); -#endif - - uboot_end = load_uboot_image(fit_blob); - - if (!uboot_end) { - panic(""); - } - - load_other_fit_images(fit_blob, uboot_end, &bl31_addr, &reservedinfo); - - if (!bl31_addr) { - uprintf("Error: BL31 (Trusted Firmware-A) not found, halting.\n"); - panic(""); - } - - if (has_sspfw) { - ssp_enable(); + /* + * Step 1: Try to boot using Caliptra Manifest + * + * If ALL steps above succeed: + * - Return BL31 entry address immediately + * + * If ANY step fails: + * - Do NOT panic here + * - Fall back to legacy FIT image boot flow + * + * NOTE: + * Caliptra Manifest boot is treated as the preferred path. + * FIT boot is kept as a compatibility mechanism. + */ + ret = load_manifest_boot_image(&jump_addr); + if (ret == CPTRA_SUCCESS) { + return jump_addr; } - if (has_tspfw) { - tsp_enable(); - } + uprintf("Caliptra boot image load failed (%d)\n", ret); - uprintf("\nJumping to BL31 (Trusted Firmware-A) at 0x%lx\n\n", - bl31_addr); - return bl31_addr; + /* + * Step 2: Fallback to FIT image boot + * + * This path scans flash for a valid FIT image, loads U-Boot first, + * then loads remaining firmware components (ATF, FDT, SSPFW, TSPFW, etc). + * + * If FIT boot fails, the system will panic. + */ + return load_fit_boot_image(); } diff --git a/ast27x0/include/ast_loader.h b/ast27x0/include/ast_loader.h new file mode 100644 index 0000000..2fe57a7 --- /dev/null +++ b/ast27x0/include/ast_loader.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2026 ASPEED Technology Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __AST27X0_INCLUDE_AST_LOADER_H__ +#define __AST27X0_INCLUDE_AST_LOADER_H__ + +#include + +void generate_crc32_table(void); +uint32_t calc_checksum(const uint8_t *data, size_t length); + +int ast_loader_read(uint64_t *dst, uint64_t src, uint32_t len); +int ast_loader_load_image(uint32_t type, uint32_t *dst); +int ast_loader_load_manifest_image(uint32_t type, uint32_t *dst); + +#endif /* __AST27X0_INCLUDE_AST_LOADER_H__ */ diff --git a/ast27x0/include/fmc_image.h b/ast27x0/include/fmc_image.h new file mode 100644 index 0000000..003ad53 --- /dev/null +++ b/ast27x0/include/fmc_image.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2025 ASPEED Technology Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __AST27X0_INCLUDE_FMC_IMAGE_H__ +#define __AST27X0_INCLUDE_FMC_IMAGE_H__ + +#include + +/* FMC v2 */ +/* ASTH */ +#define FMC_HDR_MAGIC 0x48545341 +#define ECC_SIGN_LEN 96 +#define LMS_SIGN_LEN 1620 +#define SHA_DGST_LEN 48 + +struct hdr_preamble { + uint32_t magic; + uint32_t version; + uint32_t ecc_key_idx; + uint32_t lms_key_idx; + uint8_t ecc_sig[ECC_SIGN_LEN]; + uint8_t lms_sig[LMS_SIGN_LEN]; + uint32_t raz[15]; +}; + +struct hdr_body { + uint32_t svn; + uint32_t size; + uint8_t dgst[SHA_DGST_LEN]; + /* 712 bytes */ + uint8_t reserved[178 * 4]; +}; + +struct ast_fmc_header { + struct hdr_preamble preamble; + struct hdr_body body; +} __attribute__((packed)); + +struct fmc_img_info { + uint64_t payload_start; + uint64_t payload_end; +}; + +uint64_t load_fit_boot_image(void); + +#endif /* __AST27X0_INCLUDE_FMC_IMAGE_H__ */ diff --git a/ast27x0/include/image.h b/ast27x0/include/image.h index 4fe3316..5d48767 100644 --- a/ast27x0/include/image.h +++ b/ast27x0/include/image.h @@ -17,42 +17,9 @@ #ifndef __AST27X0_INCLUDE_IMAGE_H__ #define __AST27X0_INCLUDE_IMAGE_H__ -#define DRAM_ADDR 0x400000000ULL -#define FMCCS0 0x100000000ULL +#include -/* FMC v2 */ -/* ASTH */ -#define FMC_HDR_MAGIC 0x48545341 -#define ECC_SIGN_LEN 96 -#define LMS_SIGN_LEN 1620 -#define SHA_DGST_LEN 48 - -struct hdr_preamble { - uint32_t magic; - uint32_t version; - uint32_t ecc_key_idx; - uint32_t lms_key_idx; - uint8_t ecc_sig[ECC_SIGN_LEN]; - uint8_t lms_sig[LMS_SIGN_LEN]; - uint32_t raz[15]; -}; - -struct hdr_body { - uint32_t svn; - uint32_t size; - uint8_t dgst[SHA_DGST_LEN]; - /* 712 bytes */ - uint8_t reserved[178 * 4]; -}; - -struct ast_fmc_header { - struct hdr_preamble preamble; - struct hdr_body body; -} __attribute__((packed)); - -struct fmc_img_info { - uint64_t payload_start; - uint64_t payload_end; -}; +uint64_t convert_mcu_addr_to_arm_dram(uint64_t mcu_load_addr); +void *find_and_load_appended_dtb(uint64_t start_addr, uint64_t end_addr); #endif /* __AST27X0_INCLUDE_IMAGE_H__ */ diff --git a/ast27x0/include/io.h b/ast27x0/include/io.h index 6813940..40d8297 100644 --- a/ast27x0/include/io.h +++ b/ast27x0/include/io.h @@ -35,4 +35,13 @@ #define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) +/* extract the Least Significant Bit */ +#define LSB_GET(value) ((value) & -(value)) + +/* extract a bitfield element from value corresponding to the field mask */ +#define FIELD_GET(mask, value) (((value) & (mask)) / LSB_GET(mask)) + +/* calculate number of array elements */ +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + #endif /* __AST27X0_INCLUDE_IO_H__ */ diff --git a/ast27x0/include/manifest.h b/ast27x0/include/manifest.h new file mode 100644 index 0000000..48b9d7e --- /dev/null +++ b/ast27x0/include/manifest.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2026 ASPEED Technology Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __AST27X0_INCLUDE_MANIFEST_H__ +#define __AST27X0_INCLUDE_MANIFEST_H__ + +#include +#include + +#define CPTRA_FLASH_IMG_MAGIC (0x48534C46) /* 'FLSH' in little endian */ +#define CPTRA_MBCMD_SET_AUTH_MANIFEST (0x41544D4E) /* "ATMN" */ +#define CPTRA_IMC_ENTRY_COUNT 127 + +enum { + CPTRA_MANIFEST_FW_ID = 0x00, + CPTRA_FMC_FW_ID = 0x01, + CPTRA_DDR4_IMEM_FW_ID = 0x02, + CPTRA_DDR4_DMEM_FW_ID = 0x03, + CPTRA_DDR4_2D_IMEM_FW_ID = 0x04, + CPTRA_DDR4_2D_DMEM_FW_ID = 0x05, + CPTRA_DDR5_IMEM_FW_ID = 0x06, + CPTRA_DDR5_DMEM_FW_ID = 0x07, + CPTRA_DP_FW_FW_ID = 0x08, + CPTRA_UEFI_FW_ID = 0x09, + CPTRA_ATF_FW_ID = 0x0a, + CPTRA_OPTEE_FW_ID = 0x0b, + CPTRA_UBOOT_FW_ID = 0x0c, + CPTRA_SSP_FW_ID = 0x0d, + CPTRA_TSP_FW_ID = 0x0e, +}; + +enum cptra_error_code { + CPTRA_SUCCESS = 0, + CPTRA_ERR_EXCEED_MEMORY_LIMIT, + CPTRA_ERR_INVALID_PARAMETER, + CPTRA_ERR_ABB_LOADER_NOT_READY, + CPTRA_ERR_READ_HDR, + CPTRA_ERR_HDR_MAGIC_MISMATCH, + CPTRA_ERR_EXCEED_MAX_IMG_COUNT, + CPTRA_ERR_READ_CHKSUM, + CPTRA_ERR_READ_IMG_INFO, + CPTRA_ERR_READ_FULL_IMG, + CPTRA_ERR_HDR_CHKSUM, + CPTRA_ERR_PAYLOAD_CHKSUM, + CPTRA_ERR_SOC_MANIFEST_NO_INFO, + CPTRA_ERR_SOC_MANIFEST_READ_ERROR, + CPTRA_ERR_SOC_MANIFEST_MAGIC_MISMATCH, + CPTRA_ERR_SOC_MANIFEST_VFY, + CPTRA_ERR_SOC_MANIFEST_ECC_SVN_VFY, + CPTRA_ERR_SOC_MANIFEST_LMS_SVN_VFY, + CPTRA_ERR_SOC_MANIFEST_VER_MISMATCH, + CPTRA_ERR_SHA384_CAL, + CPTRA_ERR_IMAGE_VFY_UNKNOWN_ERROR, + CPTRA_ERR_IMAGE_VFY_MBOX_ERROR, + CPTRA_ERR_IMAGE_VFY_FWID_MISMATCH, + CPTRA_ERR_IMAGE_VFY_HASH_MISMATCH, + CPTRA_ERR_IMAGE_LOAD_INVALID_PARAM, + CPTRA_ERR_IMAGE_LOAD, + CPTRA_ERR_IMAGE_READ, + CPTRA_ERR_IMAGE_SIZE_INVALID = -1, + CPTRA_ERR_IMAGE_OFFSET_INVALID = -2, +}; + +struct cptra_manifest_ime { + uint32_t fw_id; + uint32_t flags; + uint8_t digest[48]; /* SHA384 */ +}; + +struct cptra_manifest_hdr { + uint32_t magic; + uint16_t hdr_ver; + uint16_t img_count; +} __attribute__((__packed__, __aligned__(4))); + +struct cptra_checksum_info { + uint32_t hdr_checksum; + uint32_t payload_checksum; +} __attribute__((__packed__)); + +struct cptra_image_info { + uint32_t identifier; + uint32_t offset; + uint32_t size; +} __attribute__((__packed__)); + +struct cptra_manifest_aspeed_preamble { + uint32_t manifest_marker; + uint32_t preamble_size; + uint32_t manifest_version; + uint32_t manifest_sec_version; + uint32_t manifest_flags; + uint32_t manifest_vendor_ecc384_key[24]; + uint32_t manifest_vendor_lms_key[12]; + uint32_t manifest_vendor_ecc384_sig[24]; + uint32_t manifest_vendor_LMS_sig[405]; + uint32_t manifest_owner_ecc384_key[24]; + uint32_t manifest_owner_lms_key[12]; + uint32_t manifest_owner_ecc384_sig[24]; + uint32_t manifest_owner_LMS_sig[405]; + uint32_t manifest_owner_svn_ecc384_sig[24]; + uint32_t manifest_owner_svn_LMS_sig[405]; + uint32_t metadata_vendor_ecc384_sig[24]; + uint32_t metadata_vendor_LMS_sig[405]; + uint32_t metadata_owner_ecc384_sig[24]; + uint32_t metadata_owner_LMS_sig[405]; +} __attribute__((__packed__, __aligned__(4))); + +struct cptra_manifest_aspeed_svn { + uint32_t ver; + uint32_t sec_ver; + uint32_t flags; + uint32_t manifest_owner_ecc384_key[24]; + uint32_t manifest_owner_lms_key[12]; +} __attribute__((__packed__)); + +struct cptra_soc_manifest { + struct cptra_manifest_aspeed_preamble preamble; + uint32_t ime_count; + struct cptra_manifest_ime imc[CPTRA_IMC_ENTRY_COUNT]; +} __attribute__((__packed__, __aligned__(4))); + +struct cptra_image_context { + struct cptra_manifest_hdr *hdr; + struct cptra_checksum_info *chk; + struct cptra_image_info *img_info; + struct cptra_soc_manifest *soc_manifest; + uint64_t manifest_base; +}; + +int cptra_verify_abb_loader(void); +int cptra_load_abb_image(void); +int cptra_get_abb_imginfo(uint32_t fw_id, uint32_t *ofst, uint32_t *size); +void board_manifest_image_post_process(uint32_t fw_id); + +bool cptra_ime_loadable_image(struct cptra_manifest_ime *ime); +char *cptra_ime_get_image_name(uint32_t fw_id); +int cptra_ime_image_offset(struct cptra_image_context *ctx, uint32_t fw_id); +int cptra_ime_image_size(struct cptra_image_context *ctx, uint32_t fw_id); +uintptr_t cptra_ime_get_load_addr(uint32_t fw_id); + +int load_manifest_boot_image(uint64_t *jump_addr); +struct cptra_image_context *cptra_get_ctx(void); + +#endif /* __AST27X0_INCLUDE_MANIFEST_H__ */ diff --git a/ast27x0/include/platform_ast2700.h b/ast27x0/include/platform_ast2700.h new file mode 100644 index 0000000..a5e4ddf --- /dev/null +++ b/ast27x0/include/platform_ast2700.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2026 ASPEED Technology Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __AST27X0_INCLUDE_PLATFORM_AST2700_H__ +#define __AST27X0_INCLUDE_PLATFORM_AST2700_H__ + +/* DRAM base address from the hardware's perspective */ +#define SYS_DRAM_BASE 0x400000000ULL +#define ASPEED_FMC_CS0_BASE 0x100000000ULL + +#define SCU0_REG 0x12c02000 +#define SCU0_CA35_REL (SCU0_REG + 0x10c) +#define SCU0_CA35_RVBAR0 (SCU0_REG + 0x110) +#define SCU0_CA35_RVBAR1 (SCU0_REG + 0x114) +#define SCU0_CA35_RVBAR2 (SCU0_REG + 0x118) +#define SCU0_CA35_RVBAR3 (SCU0_REG + 0x11c) +#define SCU0_CPU_SMP_EP0 (SCU0_REG + 0x780) +#define SCU0_CPU_SMP_EP1 (SCU0_REG + 0x788) +#define SCU0_CPU_SMP_EP2 (SCU0_REG + 0x790) +#define SCU0_CPU_SMP_EP3 (SCU0_REG + 0x798) + +#endif /* __AST27X0_INCLUDE_PLATFORM_AST2700_H__ */ diff --git a/ast27x0/include/ssp_tsp.h b/ast27x0/include/ssp_tsp.h index 571cc0e..eff7197 100644 --- a/ast27x0/include/ssp_tsp.h +++ b/ast27x0/include/ssp_tsp.h @@ -18,6 +18,7 @@ #define __AST27X0_INCLUDE_SSP_TSP_H__ #include +#include /* MAX visible range is 512M for SSP and TSP */ #define MAX_I_D_ADDRESS (512 * 1024 * 1024) @@ -30,7 +31,7 @@ #define IPC_SSP_MEMORY_NODE "/reserved-memory/ipc-ssp-share" /* SCU */ -#define ASPEED_CPU_SCU_BASE 0x12C02000 +#define ASPEED_CPU_SCU_BASE SCU0_REG #define SCU_CPU_RST_SSP BIT(30) #define SCU_CPU_RST2_TSP BIT(9) @@ -89,7 +90,7 @@ struct ast2700_scu0 { struct mem_region { uint64_t addr; - uint32_t size; + uint64_t size; }; struct reserved_mem_info { diff --git a/ast27x0/include/stor.h b/ast27x0/include/stor.h new file mode 100644 index 0000000..69543b9 --- /dev/null +++ b/ast27x0/include/stor.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2026 ASPEED Technology Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __AST27X0_INCLUDE_STOR_H__ +#define __AST27X0_INCLUDE_STOR_H__ + +#include + +struct image_info { + int id; + uint64_t offset; + uint32_t size; +}; + +void stor_load(uint32_t type, uint32_t *dst, uint32_t *len); +const struct image_info *stor_get_image_info_table(void); +int stor_init(void); + +#endif /* __AST27X0_INCLUDE_STOR_H__ */ diff --git a/ast27x0/include/uart.h b/ast27x0/include/uart.h index 567faf4..8f16bf7 100644 --- a/ast27x0/include/uart.h +++ b/ast27x0/include/uart.h @@ -14,6 +14,8 @@ #ifndef __AST27X0_INCLUDE_UART_H__ #define __AST27X0_INCLUDE_UART_H__ +#include + #define UART12 0x14C33B00 /** @@ -31,28 +33,28 @@ extern "C" { /** @brief Parity modes */ enum uart_config_parity { - UART_CFG_PARITY_NONE, /**< No parity */ - UART_CFG_PARITY_ODD, /**< Odd parity */ - UART_CFG_PARITY_EVEN, /**< Even parity */ - UART_CFG_PARITY_MARK, /**< Mark parity */ - UART_CFG_PARITY_SPACE, /**< Space parity */ + UART_CFG_PARITY_NONE, /**< No parity */ + UART_CFG_PARITY_ODD, /**< Odd parity */ + UART_CFG_PARITY_EVEN, /**< Even parity */ + UART_CFG_PARITY_MARK, /**< Mark parity */ + UART_CFG_PARITY_SPACE, /**< Space parity */ }; /** @brief Number of stop bits. */ enum uart_config_stop_bits { - UART_CFG_STOP_BITS_0_5, /**< 0.5 stop bit */ - UART_CFG_STOP_BITS_1, /**< 1 stop bit */ - UART_CFG_STOP_BITS_1_5, /**< 1.5 stop bits */ - UART_CFG_STOP_BITS_2, /**< 2 stop bits */ + UART_CFG_STOP_BITS_0_5, /**< 0.5 stop bit */ + UART_CFG_STOP_BITS_1, /**< 1 stop bit */ + UART_CFG_STOP_BITS_1_5, /**< 1.5 stop bits */ + UART_CFG_STOP_BITS_2, /**< 2 stop bits */ }; /** @brief Number of data bits. */ enum uart_config_data_bits { - UART_CFG_DATA_BITS_5, /**< 5 data bits */ - UART_CFG_DATA_BITS_6, /**< 6 data bits */ - UART_CFG_DATA_BITS_7, /**< 7 data bits */ - UART_CFG_DATA_BITS_8, /**< 8 data bits */ - UART_CFG_DATA_BITS_9, /**< 9 data bits */ + UART_CFG_DATA_BITS_5, /**< 5 data bits */ + UART_CFG_DATA_BITS_6, /**< 6 data bits */ + UART_CFG_DATA_BITS_7, /**< 7 data bits */ + UART_CFG_DATA_BITS_8, /**< 8 data bits */ + UART_CFG_DATA_BITS_9, /**< 9 data bits */ }; /** @@ -63,21 +65,21 @@ enum uart_config_data_bits { * In other cases, flow control is managed by hardware/driver. */ enum uart_config_flow_control { - UART_CFG_FLOW_CTRL_NONE, - UART_CFG_FLOW_CTRL_RTS_CTS, - UART_CFG_FLOW_CTRL_DTR_DSR, - UART_CFG_FLOW_CTRL_RS485, + UART_CFG_FLOW_CTRL_NONE, + UART_CFG_FLOW_CTRL_RTS_CTS, + UART_CFG_FLOW_CTRL_DTR_DSR, + UART_CFG_FLOW_CTRL_RS485, }; /** * @brief UART controller configuration structure */ struct uart_config { - uint32_t baudrate; /**< Baudrate setting in bps */ - uint8_t parity; /**< Parity bit, use @ref uart_config_parity */ - uint8_t stop_bits; /**< Stop bits, use @ref uart_config_stop_bits */ - uint8_t data_bits; /**< Data bits, use @ref uart_config_data_bits */ - uint8_t flow_ctrl; /**< Flow control setting, use @ref uart_config_flow_control */ + uint32_t baudrate; /**< Baudrate setting in bps */ + uint8_t parity; /**< Parity bit, use @ref uart_config_parity */ + uint8_t stop_bits; /**< Stop bits, use @ref uart_config_stop_bits */ + uint8_t data_bits; /**< Data bits, use @ref uart_config_data_bits */ + uint8_t flow_ctrl; /**< Flow control setting, use @ref uart_config_flow_control */ }; void uart_aspeed_poll_out(unsigned char c); diff --git a/ast27x0/manifest.c b/ast27x0/manifest.c new file mode 100644 index 0000000..3d2d475 --- /dev/null +++ b/ast27x0/manifest.c @@ -0,0 +1,279 @@ +/* + * Caliptra manifest image parsing and loading. + * + * Copyright (C) 2026 ASPEED Technology Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +static struct cptra_image_context cptra_ctx; + +static int cptra_crc32_check(struct cptra_image_context *ctx) +{ + uint32_t hdr_crc32 = 0; + + /* Check the flash image header crc checksum */ + generate_crc32_table(); + hdr_crc32 = calc_checksum((uint8_t *)ctx->hdr, + sizeof(struct cptra_manifest_hdr)); + if (hdr_crc32 != ctx->chk->hdr_checksum) { + uprintf("Check flash image header checksum ...fail.\n"); + return CPTRA_ERR_HDR_CHKSUM; + } + + uprintf("Check flash image checksum ...pass.\n"); + + return CPTRA_SUCCESS; +} + +static int cptra_read_header(struct cptra_image_context *ctx) +{ + int ret = 0; + static struct cptra_manifest_hdr hdr = { 0 }; + + /* Read the manfiest header */ + ret = ast_loader_read((uint64_t *)&hdr, ctx->manifest_base, + sizeof(struct cptra_manifest_hdr)); + if (ret) { + uprintf("Failed to read manifest header.\n"); + return CPTRA_ERR_READ_HDR; + } + + if (hdr.magic != CPTRA_FLASH_IMG_MAGIC) { + uprintf("Manifest header magic mismatch: 0x%x.\n", hdr.magic); + return CPTRA_ERR_HDR_MAGIC_MISMATCH; + } + + if (hdr.img_count > CPTRA_IMC_ENTRY_COUNT) { + uprintf("Manifest image count exceeds maximum limit: %d.\n", + hdr.img_count); + return CPTRA_ERR_EXCEED_MAX_IMG_COUNT; + } + + /* The image header is correct, keep it in context */ + ctx->hdr = &hdr; + + return CPTRA_SUCCESS; +} + +static int cptra_read_chk_img_info(struct cptra_image_context *ctx) +{ + int ret = 0; + int img_num = ctx->hdr->img_count; + static uint8_t chk_img[sizeof(struct cptra_checksum_info) + + sizeof(struct cptra_image_info) * + CPTRA_IMC_ENTRY_COUNT] = { 0 }; + uint32_t ofst = sizeof(struct cptra_manifest_hdr); + uint32_t size = 0; + + if (img_num > CPTRA_IMC_ENTRY_COUNT) { + return CPTRA_ERR_EXCEED_MAX_IMG_COUNT; + } + + size = sizeof(struct cptra_checksum_info); + size += sizeof(struct cptra_image_info) * img_num; + ret = ast_loader_read((uint64_t *)chk_img, ctx->manifest_base + ofst, + size); + if (ret) { + return CPTRA_ERR_READ_IMG_INFO; + } + + ctx->chk = (struct cptra_checksum_info *)chk_img; + ctx->img_info = (struct cptra_image_info *)(chk_img + + sizeof(struct cptra_checksum_info)); + + return CPTRA_SUCCESS; +} + +static int cptra_read_abb_header(struct cptra_image_context *ctx) +{ + int ret = 0; + + /* header, checksum, img_info has been read exit directly */ + if (ctx->hdr && ctx->chk && ctx->img_info) { + return ret; + } + + ret = cptra_read_header(ctx); + if (ret) { + goto fail; + } + + ret = cptra_read_chk_img_info(ctx); + if (ret) { + goto fail; + } + + ret = cptra_crc32_check(ctx); + if (ret) { + goto fail; + } + +fail: + return ret; +} + +static int cptra_read_abb_soc_manifest(struct cptra_image_context *ctx) +{ + int ret = 0; + static struct cptra_soc_manifest soc_manifest; + + ret = ast_loader_load_image(CPTRA_MANIFEST_FW_ID, + (uint32_t *)&soc_manifest); + if (ret) { + return CPTRA_ERR_SOC_MANIFEST_READ_ERROR; + } + + if (soc_manifest.preamble.manifest_marker != + CPTRA_MBCMD_SET_AUTH_MANIFEST) + return CPTRA_ERR_SOC_MANIFEST_MAGIC_MISMATCH; + + ctx->soc_manifest = &soc_manifest; + + uprintf("ver: %x, flags: %x, soc_ver: %x\n", + soc_manifest.preamble.manifest_version, + soc_manifest.preamble.manifest_flags, + soc_manifest.preamble.manifest_sec_version); + uprintf("manfiest vendor pubk: 0x%08x\n", + soc_manifest.preamble.manifest_vendor_ecc384_key[0]); + uprintf("manfiest owner pubk: 0x%08x\n", + soc_manifest.preamble.manifest_owner_ecc384_key[0]); + + return CPTRA_SUCCESS; +} + +static void cptra_deinit_abb_loader(int ret) +{ + if (ret && cptra_ctx.hdr) { + memset(cptra_ctx.hdr, 0, sizeof(struct cptra_manifest_hdr)); + } + + if (ret && cptra_ctx.chk) { + memset(cptra_ctx.chk, 0, sizeof(struct cptra_checksum_info)); + } + + if (ret && cptra_ctx.img_info) { + memset(cptra_ctx.img_info, 0, + sizeof(struct cptra_image_info) * CPTRA_IMC_ENTRY_COUNT); + } + + if (ret && cptra_ctx.soc_manifest) { + memset(cptra_ctx.soc_manifest, 0, + sizeof(struct cptra_soc_manifest)); + } +} + +static int cptra_init_abb_loader(void) +{ + int ret = 0; + + if (cptra_ctx.hdr && cptra_ctx.img_info && cptra_ctx.chk) { + return ret; + } + + ret = cptra_read_abb_header(&cptra_ctx); + uprintf("Read abb header... %s (0x%x)\n", ret ? "fail" : "pass", ret); + + cptra_deinit_abb_loader(ret); + return ret; +} + +int cptra_verify_abb_loader(void) +{ + int ret = 0; + + if (cptra_ctx.soc_manifest) { + return ret; + } + + ret = cptra_read_abb_soc_manifest(&cptra_ctx); + uprintf("Read soc manifest... %s (0x%x)\n", ret ? "fail" : "pass", ret); + + cptra_deinit_abb_loader(ret); + return ret; +} + +int cptra_load_abb_image(void) +{ + int ret = 0; + uint32_t *load_addr = 0; + struct cptra_soc_manifest *man = cptra_ctx.soc_manifest; + struct cptra_manifest_ime *ime = &man->imc[0]; + + if (!man) { + return CPTRA_ERR_ABB_LOADER_NOT_READY; + } + + for (ime = &man->imc[0]; ime < man->imc + man->ime_count && !ret; ime++) { + /* Check the whether ime denote image should be loaded */ + if (!cptra_ime_loadable_image(ime)) { + continue; + } + + load_addr = (uint32_t *)cptra_ime_get_load_addr(ime->fw_id); + if (!load_addr) { + continue; + } + + ret = ast_loader_load_manifest_image(ime->fw_id, load_addr); + uprintf("Load %s image... %s (0x%x)\n", + cptra_ime_get_image_name(ime->fw_id), + ret ? "fail" : "pass", ret); + + if (!ret) { + board_manifest_image_post_process(ime->fw_id); + } + } + + cptra_deinit_abb_loader(ret); + return ret; +} + +int cptra_get_abb_imginfo(uint32_t fw_id, uint32_t *ofst, uint32_t *size) +{ + int ret = 0; + int image_offset = 0; + int image_size = 0; + + ret = cptra_init_abb_loader(); + if (ret) { + return ret; + } + + image_offset = cptra_ime_image_offset(&cptra_ctx, fw_id); + if (image_offset < 0) { + return CPTRA_ERR_IMAGE_READ; + } + + image_size = cptra_ime_image_size(&cptra_ctx, fw_id); + if (image_size < 0) { + return CPTRA_ERR_IMAGE_READ; + } + + *ofst = image_offset; + *size = image_size; + + return CPTRA_SUCCESS; +} + +struct cptra_image_context *cptra_get_ctx(void) +{ + return &cptra_ctx; +} + diff --git a/ast27x0/manifest_image.c b/ast27x0/manifest_image.c new file mode 100644 index 0000000..f7f2560 --- /dev/null +++ b/ast27x0/manifest_image.c @@ -0,0 +1,219 @@ +/* + * Caliptra manifest image lookup and load address helpers. + * + * Copyright (C) 2026 ASPEED Technology Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +/* Define caliptra image identifier */ +#define CPTRA_SOC_MANIFEST_HDR_ID (0x0002) +#define CPTRA_FMC_HDR_ID (0x0003) +#define CPTRA_DDR4_IMEM_HDR_ID (0x1000) +#define CPTRA_DDR4_DMEM_HDR_ID (0x1001) +#define CPTRA_DDR4_2D_IMEM_HDR_ID (0x1002) +#define CPTRA_DDR4_2D_DMEM_HDR_ID (0x1003) +#define CPTRA_DDR5_IMEM_HDR_ID (0x1004) +#define CPTRA_DDR5_DMEM_HDR_ID (0x1005) +#define CPTRA_DP_FW_HDR_ID (0x1006) +#define CPTRA_UEFI_HDR_ID (0x1007) +#define CPTRA_ATF_HDR_ID (0x1008) +#define CPTRA_OPTEE_HDR_ID (0x1009) +#define CPTRA_UBOOT_HDR_ID (0x100A) +#define CPTRA_SSP_HDR_ID (0x100B) +#define CPTRA_TSP_HDR_ID (0x100C) + +/* Define caliptra image load address */ +#define CPTRA_NO_LOAD_ADDR (0x00000000) +#define CPTRA_FMC_LOAD_ADDR (0x14b80000) +#define CPTRA_ATF_LOAD_ADDR (0xb0000000) +#define CPTRA_OPTEE_LOAD_ADDR (0xb0080000) +#define CPTRA_UBOOT_LOAD_ADDR (0x80000000) +#define CPTRA_SSP_LOAD_ADDR (0xac000000) +#define CPTRA_TSP_LOAD_ADDR (0xae000000) + +/* Define caliptra image loadable property */ +#define CPTRA_LOADABLE_MASK GENMASK(31, 30) +#define CPTRA_BOOTMCU_LOADABLE (1) +#define CPTRA_SSP_LOADABLE (2) + +struct cptra_load_image { + char *name; + uint32_t identifier; + uint32_t fw_id; + uintptr_t load_addr; +}; + +static struct cptra_load_image image_list[] = { + { "manifest", + CPTRA_SOC_MANIFEST_HDR_ID, CPTRA_MANIFEST_FW_ID, CPTRA_NO_LOAD_ADDR}, + { "mcu_fmc", + CPTRA_FMC_HDR_ID, CPTRA_FMC_FW_ID, CPTRA_FMC_LOAD_ADDR}, + { "ddr4_imem", + CPTRA_DDR4_IMEM_HDR_ID, CPTRA_DDR4_IMEM_FW_ID, CPTRA_NO_LOAD_ADDR}, + { "ddr4_dmem", + CPTRA_DDR4_DMEM_HDR_ID, CPTRA_DDR4_DMEM_FW_ID, CPTRA_NO_LOAD_ADDR}, + { "ddr4_2d_imem", + CPTRA_DDR4_2D_IMEM_HDR_ID, CPTRA_DDR4_2D_IMEM_FW_ID, CPTRA_NO_LOAD_ADDR}, + { "ddr4_2d_dmem", + CPTRA_DDR4_2D_DMEM_HDR_ID, CPTRA_DDR4_2D_DMEM_FW_ID, CPTRA_NO_LOAD_ADDR}, + { "ddr5_imem", + CPTRA_DDR5_IMEM_HDR_ID, CPTRA_DDR5_IMEM_FW_ID, CPTRA_NO_LOAD_ADDR}, + { "ddr5_dmem", + CPTRA_DDR5_DMEM_HDR_ID, CPTRA_DDR5_DMEM_FW_ID, CPTRA_NO_LOAD_ADDR}, + { "dp_fw", + CPTRA_DP_FW_HDR_ID, CPTRA_DP_FW_FW_ID, CPTRA_NO_LOAD_ADDR}, + { "uefi", + CPTRA_UEFI_HDR_ID, CPTRA_UEFI_FW_ID, CPTRA_NO_LOAD_ADDR}, + { "atf", + CPTRA_ATF_HDR_ID, CPTRA_ATF_FW_ID, CPTRA_ATF_LOAD_ADDR}, + { "optee", + CPTRA_OPTEE_HDR_ID, CPTRA_OPTEE_FW_ID, CPTRA_OPTEE_LOAD_ADDR}, + { "uboot", + CPTRA_UBOOT_HDR_ID, CPTRA_UBOOT_FW_ID, CPTRA_UBOOT_LOAD_ADDR}, + { "ssp", + CPTRA_SSP_HDR_ID, CPTRA_SSP_FW_ID, CPTRA_SSP_LOAD_ADDR}, + { "tsp", + CPTRA_TSP_HDR_ID, CPTRA_TSP_FW_ID, CPTRA_TSP_LOAD_ADDR}, +}; + +static struct cptra_image_info *cptra_find_image_info( + struct cptra_image_context *ctx, uint32_t identifier) +{ + bool match = false; + uint32_t img_num = ctx->hdr->img_count; + struct cptra_image_info *img_info = ctx->img_info; + + if (img_num > CPTRA_IMC_ENTRY_COUNT + 2) { + return NULL; + } + + for (img_info = ctx->img_info; + img_info < ctx->img_info + img_num; + img_info++) { + if (img_info->identifier == identifier) { + match = true; + break; + } + } + + return match ? img_info : NULL; +} + +static int cptra_img_info_get_offset(struct cptra_image_context *ctx, + uint32_t identifier) +{ + struct cptra_image_info *img_info = NULL; + + img_info = cptra_find_image_info(ctx, identifier); + + return img_info ? (int)img_info->offset : CPTRA_ERR_IMAGE_OFFSET_INVALID; +} + +static int cptra_img_info_get_size(struct cptra_image_context *ctx, + uint32_t identifier) +{ + struct cptra_image_info *img_info = NULL; + + img_info = cptra_find_image_info(ctx, identifier); + + return img_info ? (int)img_info->size : CPTRA_ERR_IMAGE_SIZE_INVALID; +} + +static struct cptra_load_image *cptra_find_load_image(uint32_t fw_id) +{ + int i = 0; + int match = -1; + + for (i = 0; i < (int)ARRAY_SIZE(image_list) && match == -1; i++) { + match = image_list[i].fw_id == fw_id ? i : match; + } + + return match != -1 ? &image_list[match] : NULL; +} + +bool cptra_ime_loadable_image(struct cptra_manifest_ime *ime) +{ + if (!ime) { + return false; + } + + if (FIELD_GET(CPTRA_LOADABLE_MASK, ime->flags) == CPTRA_BOOTMCU_LOADABLE) { + return true; + } + + return false; +} + +int cptra_ime_image_offset(struct cptra_image_context *ctx, uint32_t fw_id) +{ + struct cptra_load_image *img = NULL; + + if (!ctx) { + return CPTRA_ERR_IMAGE_OFFSET_INVALID; + } + + img = cptra_find_load_image(fw_id); + if (!img) { + uprintf("Cannot find image with fw_id 0x%x.\n", fw_id); + return CPTRA_ERR_IMAGE_OFFSET_INVALID; + } + + return cptra_img_info_get_offset(ctx, img->identifier); +} + +char *cptra_ime_get_image_name(uint32_t fw_id) +{ + struct cptra_load_image *img = NULL; + + img = cptra_find_load_image(fw_id); + + return img ? img->name : "Unknown"; +} + +int cptra_ime_image_size(struct cptra_image_context *ctx, uint32_t fw_id) +{ + struct cptra_load_image *img = NULL; + + if (!ctx) { + return CPTRA_ERR_IMAGE_SIZE_INVALID; + } + + img = cptra_find_load_image(fw_id); + if (!img) { + uprintf("Cannot find image with fw_id 0x%x.\n", fw_id); + return CPTRA_ERR_IMAGE_SIZE_INVALID; + } + + return cptra_img_info_get_size(ctx, img->identifier); +} + +uintptr_t cptra_ime_get_load_addr(uint32_t fw_id) +{ + struct cptra_load_image *img = NULL; + + img = cptra_find_load_image(fw_id); + if (!img) { + uprintf("Cannot find image with fw_id 0x%x.\n", fw_id); + return (uintptr_t)NULL; + } + + return img->load_addr; +} + diff --git a/ast27x0/ssp_tsp.c b/ast27x0/ssp_tsp.c index 6bbeef0..7d790a3 100644 --- a/ast27x0/ssp_tsp.c +++ b/ast27x0/ssp_tsp.c @@ -19,6 +19,7 @@ #include #include #include +#include void get_reserved_memory(const void *fdt_blob, struct reserved_mem_info *info) { @@ -35,30 +36,69 @@ void get_reserved_memory(const void *fdt_blob, struct reserved_mem_info *info) const fdt32_t *reg; const char *path; + int size_cells; + int addr_cells; + uint64_t addr; + uint64_t size; int offset; + int parent; size_t i; + int len; + int j; - for (i = 0; i < sizeof(nodes) / sizeof(nodes[0]); i++) { + for (i = 0; i < ARRAY_SIZE(nodes); i++) { path = nodes[i].path; + nodes[i].region->addr = 0; + nodes[i].region->size = 0; + addr = 0; + size = 0; offset = fdt_path_offset(fdt_blob, path); if (offset < 0) { uprintf("Cannot find node %s in the device tree.\n", path); - nodes[i].region->addr = 0; - nodes[i].region->size = 0; continue; } - reg = fdt_getprop(fdt_blob, offset, "reg", NULL); + parent = fdt_parent_offset(fdt_blob, offset); + addr_cells = fdt_address_cells(fdt_blob, parent); + size_cells = fdt_size_cells(fdt_blob, parent); + + if (addr_cells < 0 || addr_cells > 2) { + uprintf("unsupported addr_cells: %d\n", addr_cells); + continue; + } + + if (size_cells < 0 || size_cells > 2) { + uprintf("unsupported size_cells: %d\n", size_cells); + continue; + } + + reg = fdt_getprop(fdt_blob, offset, "reg", &len); if (!reg) { uprintf("No reg property found in %s\n", path); - nodes[i].region->addr = 0; - nodes[i].region->size = 0; continue; } - nodes[i].region->addr = fdt32_to_cpu(reg[0]); - nodes[i].region->size = fdt32_to_cpu(reg[1]); + if (len < (addr_cells + size_cells) * (int)sizeof(fdt32_t)) { + uprintf("reg too short in %s (len=%d)\n", path, len); + continue; + } + + for (j = 0; j < addr_cells; j++) { + addr = (addr << 32) | (uint64_t)fdt32_to_cpu(reg[j]); + } + + for (j = 0; j < size_cells; j++) { + size = (size << 32) | (uint64_t)fdt32_to_cpu(reg[j + addr_cells]); + } + + /* convert to Arm view */ + if (addr_cells == 1) { + addr = convert_mcu_addr_to_arm_dram(addr); + } + + nodes[i].region->addr = addr; + nodes[i].region->size = size; uprintf("[reserved] %s base: 0x%lx size: 0x%lx\n", path, nodes[i].region->addr, nodes[i].region->size); @@ -70,6 +110,12 @@ int ssp_init(uint64_t load_addr, const struct reserved_mem_info *info) struct ast2700_scu0 *scu; uint32_t reg_val; + if (load_addr != info->ssp.addr) { + uprintf("load address %lx doesn't match SSP reserved memory %lx\n", + load_addr, info->ssp.addr); + return 1; + } + scu = (struct ast2700_scu0 *)ASPEED_CPU_SCU_BASE; reg_val = readl((void *)&scu->ssp_ctrl_0); @@ -113,7 +159,7 @@ int ssp_init(uint64_t load_addr, const struct reserved_mem_info *info) writel(TCM_SIZE, (void *)&scu->ssp_tcm_size); /* Configure physical AHB remap: through H2M, mapped to SYS_DRAM_BASE */ - writel((uint32_t)(DRAM_ADDR >> 4), (void *)&scu->ssp_ctrl_1); + writel((uint32_t)(SYS_DRAM_BASE >> 4), (void *)&scu->ssp_ctrl_1); /* Configure physical DRAM remap */ reg_val = (uint32_t)(load_addr >> 4); @@ -151,6 +197,12 @@ int tsp_init(uint64_t load_addr, const struct reserved_mem_info *info) struct ast2700_scu0 *scu; uint32_t reg_val; + if (load_addr != info->tsp.addr) { + uprintf("load address %lx doesn't match TSP reserved memory %lx\n", + load_addr, info->tsp.addr); + return 1; + } + scu = (struct ast2700_scu0 *)ASPEED_CPU_SCU_BASE; reg_val = readl((void *)&scu->tsp_ctrl_0); diff --git a/ast27x0/stor.c b/ast27x0/stor.c new file mode 100644 index 0000000..832a72c --- /dev/null +++ b/ast27x0/stor.c @@ -0,0 +1,106 @@ +/* + * Caliptra manifest storage helpers. + * + * Query firmware image offset and size from Caliptra Manifest and provide + * stor_load() to load images from manifest storage into destination memory. + * + * Copyright (C) 2026 ASPEED Technology Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#define DEBUG 0 + +static struct image_info img_info[] = { + {CPTRA_MANIFEST_FW_ID, 0, 0}, + {CPTRA_FMC_FW_ID, 0, 0}, + {CPTRA_DDR4_IMEM_FW_ID, 0, 0}, + {CPTRA_DDR4_DMEM_FW_ID, 0, 0}, + {CPTRA_DDR4_2D_IMEM_FW_ID, 0, 0}, + {CPTRA_DDR4_2D_DMEM_FW_ID, 0, 0}, + {CPTRA_DDR5_IMEM_FW_ID, 0, 0}, + {CPTRA_DDR5_DMEM_FW_ID, 0, 0}, + {CPTRA_DP_FW_FW_ID, 0, 0}, + {CPTRA_UEFI_FW_ID, 0, 0}, + {CPTRA_ATF_FW_ID, 0, 0}, + {CPTRA_OPTEE_FW_ID, 0, 0}, + {CPTRA_UBOOT_FW_ID, 0, 0}, + {CPTRA_SSP_FW_ID, 0, 0}, + {CPTRA_TSP_FW_ID, 0, 0}, +}; + +static int stor_get_image_info(struct image_info *info) +{ + struct cptra_image_context *cptra_ctx = cptra_get_ctx(); + uint32_t offset, sz; + int err; + + if (!info) { + uprintf("Image info pointer is NULL.\n"); + return -1; + } + + for (int i = 0; i < CPTRA_TSP_FW_ID + 1; i++) { + /* Call cptra's service to get the image info */ + err = cptra_get_abb_imginfo(info[i].id, &offset, &sz); + if (err) { + uprintf("Failed to get image info for ID %d, err=%d\n", + info[i].id, err); + return err; + } + + info[i].offset = offset + cptra_ctx->manifest_base; + info[i].size = sz; +#if DEBUG + uprintf("%s: offset=0x%lx, size=%d\n", + cptra_ime_get_image_name(info[i].id), + info[i].offset, info[i].size); +#endif + } + + return err; +} + +void stor_load(uint32_t type, uint32_t *dst, uint32_t *len) +{ + uint64_t src; + uint64_t dram_addr; + uint32_t sz = 0; + + src = img_info[type].offset; + sz = img_info[type].size; + + /* convert to Arm view */ + dram_addr = convert_mcu_addr_to_arm_dram((uint64_t)dst); + uprintf("%s: %s, dst=0x%lx, src=0x%lx, len=%d\n", __func__, + cptra_ime_get_image_name(img_info[type].id), + dram_addr, (unsigned long long)src, sz); + memcpy((void *)(uintptr_t)dram_addr, (void *)(uintptr_t)src, sz); + *len = sz; +} + +const struct image_info *stor_get_image_info_table(void) +{ + return img_info; +} + +int stor_init(void) +{ + return stor_get_image_info(img_info); +} +