| // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later |
| /* |
| * Parse VERSION partition, add to device tree |
| * |
| * Copyright 2013-2018 IBM Corp. |
| */ |
| |
| #include <skiboot.h> |
| #include <device.h> |
| #include <opal.h> |
| #include <libstb/secureboot.h> |
| #include <libstb/trustedboot.h> |
| |
| /* ibm,firmware-versions support */ |
| static char *version_buf; |
| static size_t version_buf_size = 0x2000; |
| |
| static void __flash_dt_add_fw_version(struct dt_node *fw_version, char* data) |
| { |
| static bool first = true; |
| char *prop; |
| int version_len, i; |
| int len = strlen(data); |
| const char *skiboot_version; |
| const char * version_str[] = {"open-power", "buildroot", "skiboot", |
| "hostboot-binaries", "hostboot", "linux", |
| "petitboot", "occ", "capp-ucode", "sbe", |
| "machine-xml", "hcode"}; |
| |
| if (first) { |
| first = false; |
| |
| /* Increment past "key-" */ |
| if (memcmp(data, "open-power", strlen("open-power")) == 0) |
| prop = data + strlen("open-power"); |
| else |
| prop = strchr(data, '-'); |
| if (!prop) { |
| prlog(PR_DEBUG, |
| "FLASH: Invalid fw version format (%s)\n", data); |
| return; |
| } |
| prop++; |
| |
| dt_add_property_string(fw_version, "version", prop); |
| return; |
| } |
| |
| /* |
| * PNOR version strings are not easily consumable. Split them into |
| * property, value. |
| * |
| * Example input from PNOR : |
| * "open-power-firestone-v1.8" |
| * "linux-4.4.6-openpower1-8420e0f" |
| * |
| * Desired output in device tree: |
| * open-power = "firestone-v1.8"; |
| * linux = "4.4.6-openpower1-8420e0f"; |
| */ |
| for(i = 0; i < ARRAY_SIZE(version_str); i++) |
| { |
| version_len = strlen(version_str[i]); |
| if (len < version_len) |
| continue; |
| |
| if (memcmp(data, version_str[i], version_len) != 0) |
| continue; |
| |
| /* Found a match, add property */ |
| if (dt_find_property(fw_version, version_str[i])) |
| continue; |
| |
| /* Increment past "key-" */ |
| prop = data + version_len + 1; |
| dt_add_property_string(fw_version, version_str[i], prop); |
| |
| /* Sanity check against what Skiboot thinks its version is. */ |
| if (strncmp(version_str[i], "skiboot", |
| strlen("skiboot")) == 0) { |
| /* |
| * If Skiboot was built with Buildroot its version may |
| * include a 'skiboot-' prefix; ignore it. |
| */ |
| if (strncmp(version, "skiboot-", |
| strlen("skiboot-")) == 0) |
| skiboot_version = version + strlen("skiboot-"); |
| else |
| skiboot_version = version; |
| if (strncmp(prop, skiboot_version, |
| strlen(skiboot_version)) != 0) |
| prlog(PR_WARNING, "WARNING! Skiboot version does not match VERSION partition!\n"); |
| } |
| } |
| } |
| |
| void flash_dt_add_fw_version(void) |
| { |
| uint8_t version_data[80]; |
| int rc; |
| int numbytes = 0, i = 0; |
| struct dt_node *fw_version; |
| |
| if (version_buf == NULL) |
| return; |
| |
| rc = wait_for_resource_loaded(RESOURCE_ID_VERSION, RESOURCE_SUBID_NONE); |
| if (rc != OPAL_SUCCESS) { |
| prlog(PR_WARNING, "FLASH: Failed to load VERSION data\n"); |
| free(version_buf); |
| return; |
| } |
| |
| fw_version = dt_new(dt_root, "ibm,firmware-versions"); |
| assert(fw_version); |
| |
| if (stb_is_container(version_buf, version_buf_size)) |
| numbytes += SECURE_BOOT_HEADERS_SIZE; |
| for ( ; (numbytes < version_buf_size) && version_buf[numbytes]; numbytes++) { |
| if (version_buf[numbytes] == '\n') { |
| version_data[i] = '\0'; |
| __flash_dt_add_fw_version(fw_version, version_data); |
| memset(version_data, 0, sizeof(version_data)); |
| i = 0; |
| continue; |
| } else if (version_buf[numbytes] == '\t') { |
| continue; /* skip tabs */ |
| } |
| |
| version_data[i++] = version_buf[numbytes]; |
| if (i == sizeof(version_data)) { |
| prlog(PR_WARNING, "VERSION item >%lu chars, skipping\n", |
| sizeof(version_data)); |
| break; |
| } |
| } |
| |
| free(version_buf); |
| } |
| |
| void flash_fw_version_preload(void) |
| { |
| int rc; |
| |
| if (proc_gen < proc_gen_p9) |
| return; |
| |
| prlog(PR_INFO, "FLASH: Loading VERSION section\n"); |
| |
| version_buf = malloc(version_buf_size); |
| if (!version_buf) { |
| prlog(PR_WARNING, "FLASH: Failed to allocate memory\n"); |
| return; |
| } |
| |
| rc = start_preload_resource(RESOURCE_ID_VERSION, RESOURCE_SUBID_NONE, |
| version_buf, &version_buf_size); |
| if (rc != OPAL_SUCCESS) { |
| prlog(PR_WARNING, |
| "FLASH: Failed to start loading VERSION data\n"); |
| free(version_buf); |
| version_buf = NULL; |
| } |
| } |