Files
rocm-systems/src/ras-decode/boot_decode.c
T
Saeed, Oosman 90f4b8c43d Sync with latest ras-decode @bc6b43c (#770)
Signed-off-by: Oosman Saeed <oossaeed@amd.com>
2025-10-27 14:10:00 -05:00

753 lines
27 KiB
C

/*
* Copyright (c) Advanced Micro Devices, 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 "boot_decode.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ras_decode_constants.h"
// Boot decoder mapping tables
static const boot_decoder_entry_t boot_decoder_map_v0[] = {
{BOOT_ENCODING_HBM_TRAINING, decode_hbm_training_v0},
{BOOT_ENCODING_FW_LOAD, decode_fw_load_v0},
{BOOT_ENCODING_WAFL_LINK, decode_wafl_link_training_v0},
{BOOT_ENCODING_XGMI_LINK, decode_xgmi_link_training_v0},
{BOOT_ENCODING_USR_CP_LINK, decode_usr_cp_link_training_v0},
{BOOT_ENCODING_USR_DP_LINK, decode_usr_dp_link_training_v0},
{BOOT_ENCODING_HBM_MEM_TEST, decode_hbm_mem_test_v0},
{BOOT_ENCODING_HBM_BIST_TEST, decode_hbm_bist_test_v0},
{BOOT_ENCODING_BOOT_CTRL_GEN_V0, decode_boot_controller_generic_v0},
{0, NULL} // Sentinel
};
static const boot_decoder_entry_t boot_decoder_map_v1[] = {
{BOOT_ENCODING_HBM_TRAINING, decode_hbm_training_v1},
{BOOT_ENCODING_FW_LOAD, decode_fw_load_v1},
{BOOT_ENCODING_WAFL_LINK, decode_wafl_link_training_v1},
{BOOT_ENCODING_XGMI_LINK, decode_xgmi_link_training_v1},
{BOOT_ENCODING_USR_CP_LINK, decode_usr_cp_link_training_v1},
{BOOT_ENCODING_USR_DP_LINK, decode_usr_dp_link_training_v1},
{BOOT_ENCODING_HBM_MEM_TEST, decode_hbm_mem_test_v1},
{BOOT_ENCODING_HBM_BIST_TEST, decode_hbm_bist_test_v1},
{BOOT_ENCODING_BOOT_CTRL_GEN_V1, decode_boot_controller_generic_v1},
{BOOT_ENCODING_DATA_ABORT, decode_data_abort_v1},
{BOOT_SUCCESS_ENCODING, decode_boot_success_v1},
{0, NULL} // Sentinel
};
int get_boot_version(OamBootMsg *msg) {
if (!msg) return 0;
return extract_byte(msg->value, 1) >> 5;
}
int get_error_encoding(OamBootMsg *msg) {
if (!msg) return 0;
return (int)(extract_byte(msg->value, 1) & extract_bits(5));
}
bool error_present(OamBootMsg *msg) {
if (!msg) return false;
return extract_byte(msg->value, 0) == BOOT_ERROR_PRESENT_MARKER;
}
bool in_boot(OamBootMsg *msg) {
if (!msg) return false;
return extract_byte(msg->value, 0) == BOOT_IN_BOOT_MARKER;
}
int get_socket(OamBootMsg *msg, int version) {
if (!msg) return 0;
if (version == 0) {
return extract_byte(msg->value, 4);
} else {
return (int)((extract_byte(msg->value, 2) >> 4) & extract_bits(4));
}
}
int get_aid(OamBootMsg *msg, int version) {
if (!msg) return 0;
if (version == 0) {
return extract_byte(msg->value, 5);
} else {
return (int)(extract_byte(msg->value, 2) & extract_bits(4));
}
}
int decode_hbm_stack(uint8_t stack) {
switch (stack) {
case HBM_STACK_0:
return 0;
case HBM_STACK_1:
return 1;
default:
return HBM_STACK_UNKNOWN;
}
}
JsonValue *create_failed_links_array(uint8_t byte_value, int max_links) {
JsonValue *array = json_create_array();
if (!array) return NULL;
for (int i = 0; i < max_links; i++) {
if ((byte_value >> i) & 0x1) {
JsonValue *link_num = json_create_number(i);
if (link_num) {
json_array_push(array, link_num);
}
}
}
return array;
}
char *create_hex_string(uint64_t value, int width) {
if (width < 0) return NULL;
size_t buffer_size = (size_t)width + 3U; // '0' + 'x' + width digits + '\0'
char *hex_str = malloc(buffer_size);
if (!hex_str) return NULL;
snprintf(hex_str, buffer_size, "0x%0*llX", width, (unsigned long long)value);
return hex_str;
}
// Version 0 decoder implementations
JsonValue *decode_hbm_training_v0(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte3 = extract_byte(msg->value, 3);
uint8_t byte2 = extract_byte(msg->value, 2);
json_object_set(result, "error_type", json_create_string(RAS_DECODE_ERROR_TYPE_HBM_TRAINING));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "hbm_stack", json_create_number(decode_hbm_stack(byte3)));
json_object_set(result, "hbm_channel", json_create_number(byte2));
return result;
}
JsonValue *decode_fw_load_v0(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte3 = extract_byte(msg->value, 3);
uint8_t byte2 = extract_byte(msg->value, 2);
uint16_t fw_id = (uint16_t)((byte3 << 8) | byte2);
char *fw_id_str = create_hex_string(fw_id, 4);
json_object_set(result, "error_type", json_create_string(RAS_DECODE_ERROR_TYPE_FW_LOAD));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "fw_id", json_create_string(fw_id_str ? fw_id_str : "0x0000"));
free(fw_id_str);
return result;
}
JsonValue *decode_wafl_link_training_v0(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte2 = extract_byte(msg->value, 2);
JsonValue *failed_links = create_failed_links_array(byte2, 2);
json_object_set(result, "error_type",
json_create_string(RAS_DECODE_ERROR_TYPE_WAFL_LINK_TRAINING));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "failed_links", failed_links ? failed_links : json_create_array());
return result;
}
JsonValue *decode_xgmi_link_training_v0(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte2 = extract_byte(msg->value, 2);
JsonValue *failed_links = create_failed_links_array(byte2, 8);
json_object_set(result, "error_type",
json_create_string(RAS_DECODE_ERROR_TYPE_XGMI_LINK_TRAINING));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "failed_links", failed_links ? failed_links : json_create_array());
return result;
}
JsonValue *decode_usr_cp_link_training_v0(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte2 = extract_byte(msg->value, 2);
JsonValue *failed_links = create_failed_links_array(byte2, 2);
json_object_set(result, "error_type",
json_create_string(RAS_DECODE_ERROR_TYPE_USR_CP_LINK_TRAINING));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "failed_links", failed_links ? failed_links : json_create_array());
return result;
}
JsonValue *decode_usr_dp_link_training_v0(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte2 = extract_byte(msg->value, 2);
JsonValue *failed_links = create_failed_links_array(byte2, 4);
json_object_set(result, "error_type",
json_create_string(RAS_DECODE_ERROR_TYPE_USR_DP_LINK_TRAINING));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "failed_links", failed_links ? failed_links : json_create_array());
return result;
}
JsonValue *decode_hbm_mem_test_v0(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte3 = extract_byte(msg->value, 3);
uint8_t byte2 = extract_byte(msg->value, 2);
json_object_set(result, "error_type", json_create_string(RAS_DECODE_ERROR_TYPE_HBM_MEMORY_TEST));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "hbm_stack", json_create_number(decode_hbm_stack(byte3)));
json_object_set(result, "hbm_channel", json_create_number(byte2));
return result;
}
JsonValue *decode_hbm_bist_test_v0(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte3 = extract_byte(msg->value, 3);
uint8_t byte2 = extract_byte(msg->value, 2);
json_object_set(result, "error_type", json_create_string(RAS_DECODE_ERROR_TYPE_HBM_BIST_TEST));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "hbm_stack", json_create_number(decode_hbm_stack(byte3)));
json_object_set(result, "hbm_channel", json_create_number(byte2));
return result;
}
JsonValue *decode_boot_controller_generic_v0(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
json_object_set(result, "error_type",
json_create_string(RAS_DECODE_ERROR_TYPE_BOOT_CONTROLLER_GENERIC));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
return result;
}
// Version 1 decoder implementations
JsonValue *decode_hbm_training_v1(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte5 = extract_byte(msg->value, 5);
uint8_t byte4 = extract_byte(msg->value, 4);
json_object_set(result, "error_type", json_create_string(RAS_DECODE_ERROR_TYPE_HBM_TRAINING));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "hbm_stack", json_create_number(decode_hbm_stack(byte5)));
json_object_set(result, "hbm_channel", json_create_number(byte4));
return result;
}
JsonValue *decode_fw_load_v1(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte5 = extract_byte(msg->value, 5);
uint8_t byte4 = extract_byte(msg->value, 4);
uint16_t fw_id = (uint16_t)((byte5 << 8) | byte4);
char *fw_id_str = create_hex_string(fw_id, 4);
json_object_set(result, "error_type", json_create_string(RAS_DECODE_ERROR_TYPE_FW_LOAD));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "fw_id", json_create_string(fw_id_str ? fw_id_str : "0x0000"));
free(fw_id_str);
return result;
}
JsonValue *decode_wafl_link_training_v1(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte4 = extract_byte(msg->value, 4);
JsonValue *failed_links = create_failed_links_array(byte4, 2);
json_object_set(result, "error_type",
json_create_string(RAS_DECODE_ERROR_TYPE_WAFL_LINK_TRAINING));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "failed_links", failed_links ? failed_links : json_create_array());
return result;
}
JsonValue *decode_xgmi_link_training_v1(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte4 = extract_byte(msg->value, 4);
JsonValue *failed_links = create_failed_links_array(byte4, 8);
json_object_set(result, "error_type",
json_create_string(RAS_DECODE_ERROR_TYPE_XGMI_LINK_TRAINING));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "failed_links", failed_links ? failed_links : json_create_array());
return result;
}
JsonValue *decode_usr_cp_link_training_v1(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte4 = extract_byte(msg->value, 4);
JsonValue *failed_links = create_failed_links_array(byte4, 2);
json_object_set(result, "error_type",
json_create_string(RAS_DECODE_ERROR_TYPE_USR_CP_LINK_TRAINING));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "failed_links", failed_links ? failed_links : json_create_array());
return result;
}
JsonValue *decode_usr_dp_link_training_v1(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte4 = extract_byte(msg->value, 4);
JsonValue *failed_links = create_failed_links_array(byte4, 4);
json_object_set(result, "error_type",
json_create_string(RAS_DECODE_ERROR_TYPE_USR_DP_LINK_TRAINING));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "failed_links", failed_links ? failed_links : json_create_array());
return result;
}
JsonValue *decode_hbm_mem_test_v1(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte5 = extract_byte(msg->value, 5);
uint8_t byte4 = extract_byte(msg->value, 4);
json_object_set(result, "error_type", json_create_string(RAS_DECODE_ERROR_TYPE_HBM_MEMORY_TEST));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "hbm_stack", json_create_number(decode_hbm_stack(byte5)));
json_object_set(result, "hbm_channel", json_create_number(byte4));
return result;
}
JsonValue *decode_hbm_bist_test_v1(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte5 = extract_byte(msg->value, 5);
uint8_t byte4 = extract_byte(msg->value, 4);
json_object_set(result, "error_type", json_create_string(RAS_DECODE_ERROR_TYPE_HBM_BIST_TEST));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "hbm_stack", json_create_number(decode_hbm_stack(byte5)));
json_object_set(result, "hbm_channel", json_create_number(byte4));
return result;
}
JsonValue *decode_boot_controller_generic_v1(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte4 = extract_byte(msg->value, 4);
uint8_t byte0 = extract_byte(msg->value, 0);
uint8_t byte5 = extract_byte(msg->value, 5);
uint8_t byte6 = extract_byte(msg->value, 6);
uint8_t byte7 = extract_byte(msg->value, 7);
char *boot_step_str = create_hex_string(byte4, 2);
uint32_t boot_status = (uint32_t)((byte7 << 24) | (byte6 << 16) | (byte5 << 8) | byte0);
char *boot_status_str = create_hex_string(boot_status, 8);
json_object_set(result, "error_type",
json_create_string(RAS_DECODE_ERROR_TYPE_BOOT_CONTROLLER_GENERIC));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "last_successful_boot_step_number",
json_create_string(boot_step_str ? boot_step_str : "0x00"));
json_object_set(result, "fw_boot_status",
json_create_string(boot_status_str ? boot_status_str : "0x00000000"));
free(boot_step_str);
free(boot_status_str);
return result;
}
JsonValue *decode_data_abort_v1(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
int version = get_boot_version(msg);
uint8_t byte3 = extract_byte(msg->value, 3);
uint8_t byte4 = extract_byte(msg->value, 4);
uint8_t byte5 = extract_byte(msg->value, 5);
uint8_t byte6 = extract_byte(msg->value, 6);
uint8_t byte7 = extract_byte(msg->value, 7);
char *boot_step_str = create_hex_string(byte3, 2);
uint32_t exception_addr = (uint32_t)((byte7 << 24) | (byte6 << 16) | (byte5 << 8) | byte4);
char *exception_addr_str = create_hex_string(exception_addr, 8);
json_object_set(result, "error_type",
json_create_string(RAS_DECODE_ERROR_TYPE_BOOT_CONTROLLER_DATA_ABORT));
json_object_set(result, "socket", json_create_number(get_socket(msg, version)));
json_object_set(result, "aid", json_create_number(get_aid(msg, version)));
json_object_set(result, "last_successful_boot_step_number",
json_create_string(boot_step_str ? boot_step_str : "0x00"));
json_object_set(result, "exception_address",
json_create_string(exception_addr_str ? exception_addr_str : "0x00000000"));
free(boot_step_str);
free(exception_addr_str);
return result;
}
JsonValue *decode_boot_success_v1(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
uint8_t byte4 = extract_byte(msg->value, 4);
uint8_t byte0 = extract_byte(msg->value, 0);
uint8_t byte5 = extract_byte(msg->value, 5);
uint8_t byte6 = extract_byte(msg->value, 6);
uint8_t byte7 = extract_byte(msg->value, 7);
char *boot_step_str = create_hex_string(byte4, 2);
uint32_t boot_status = (uint32_t)((byte7 << 24) | (byte6 << 16) | (byte5 << 8) | byte0);
char *boot_status_str = create_hex_string(boot_status, 8);
json_object_set(result, "error_type", json_create_string(RAS_DECODE_ERROR_TYPE_BOOT_SUCCESS));
json_object_set(result, "last_successful_boot_step_number",
json_create_string(boot_step_str ? boot_step_str : "0x00"));
json_object_set(result, "fw_boot_status",
json_create_string(boot_status_str ? boot_status_str : "0x00000000"));
free(boot_step_str);
free(boot_status_str);
return result;
}
// Unhandled error decoders
JsonValue *decode_unhandled_error_v0(OamBootMsg *msg) {
(void)msg; // Suppress unused parameter warning
JsonValue *result = json_create_object();
if (!result) return NULL;
json_object_set(result, "error_type", json_create_string(RAS_DECODE_ERROR_TYPE_UNHANDLED));
return result;
}
JsonValue *decode_unhandled_error_v1(OamBootMsg *msg) {
if (!msg) return NULL;
JsonValue *result = json_create_object();
if (!result) return NULL;
uint8_t byte4 = extract_byte(msg->value, 4);
uint8_t byte0 = extract_byte(msg->value, 0);
uint8_t byte5 = extract_byte(msg->value, 5);
uint8_t byte6 = extract_byte(msg->value, 6);
uint8_t byte7 = extract_byte(msg->value, 7);
char *boot_step_str = create_hex_string(byte4, 2);
uint32_t boot_status = (uint32_t)((byte7 << 24) | (byte6 << 16) | (byte5 << 8) | byte0);
char *boot_status_str = create_hex_string(boot_status, 8);
json_object_set(result, "error_type", json_create_string(RAS_DECODE_ERROR_TYPE_UNHANDLED));
json_object_set(result, "last_successful_boot_step_number",
json_create_string(boot_step_str ? boot_step_str : "0x00"));
json_object_set(result, "fw_boot_status",
json_create_string(boot_status_str ? boot_status_str : "0x00000000"));
free(boot_step_str);
free(boot_status_str);
return result;
}
boot_decoder_func_t get_decoder_function(OamBootMsg *msg) {
if (!msg) return NULL;
uint8_t byte0 = extract_byte(msg->value, 0);
if (byte0 == BOOT_IN_BOOT_MARKER) {
int version = get_boot_version(msg);
if (version == 1) {
return decode_boot_success_v1;
}
}
int version = get_boot_version(msg);
int encoding = get_error_encoding(msg);
const boot_decoder_entry_t *decoder_map =
(version == 0) ? boot_decoder_map_v0 : boot_decoder_map_v1;
for (int i = 0; decoder_map[i].decoder != NULL; i++) {
if (decoder_map[i].encoding == encoding) {
return decoder_map[i].decoder;
}
}
return NULL; // No decoder found
}
JsonValue *boot_decode_orchestrator(const uint64_t *oam_boot_msgs, size_t count) {
if (!oam_boot_msgs || count == 0) return NULL;
JsonValue *results = json_create_object();
if (!results) return NULL;
// Convert to OamBootMsg structures
OamBootMsg *msgs = malloc(count * sizeof(OamBootMsg));
if (!msgs) {
json_free(results);
return NULL;
}
for (size_t i = 0; i < count; i++) {
msgs[i].value = oam_boot_msgs[i];
}
// Check error markers across all messages
size_t messages_with_markers = 0;
bool *has_marker = malloc(count * sizeof(bool));
if (!has_marker) {
free(msgs);
json_free(results);
return NULL;
}
// Count messages with error markers (0xA4) or boot markers (0xBA)
for (size_t i = 0; i < count; i++) {
has_marker[i] = error_present(&msgs[i]) || in_boot(&msgs[i]);
if (has_marker[i]) {
messages_with_markers++;
}
}
// Determine decoding strategy based on the presence of error markers
bool decode_all_as_unhandled = (messages_with_markers == 0);
bool decode_only_marked = (messages_with_markers > 0 && messages_with_markers < count);
bool decode_all_normally = (messages_with_markers == count);
// Check if all decoders are NULL (for unhandled error handling)
bool all_decoders_none = true;
if (!decode_all_as_unhandled) {
for (size_t i = 0; i < count; i++) {
if (has_marker[i] && get_decoder_function(&msgs[i]) != NULL) {
all_decoders_none = false;
break;
}
}
}
// Process each message
for (size_t i = 0; i < count; i++) {
char msg_key[32];
snprintf(msg_key, sizeof(msg_key), "msg%zu", i);
// Skip messages without markers if we're in selective decode mode
if (decode_only_marked && !has_marker[i]) {
continue;
}
JsonValue *msg_result = json_create_object();
if (!msg_result) continue;
boot_decoder_func_t decoder_func = NULL;
if (decode_all_as_unhandled) {
// Rule 3: No messages have markers, decode all as UNHANDLED
decoder_func = decode_unhandled_error_v1;
} else if (has_marker[i] || decode_all_normally) {
// Rule 1 & 2: Decode messages with markers (or all if all have markers)
if (all_decoders_none) {
// Use unhandled error decoders
int encoding = get_error_encoding(&msgs[i]);
decoder_func = (encoding == 0) ? decode_unhandled_error_v0 : decode_unhandled_error_v1;
} else {
decoder_func = get_decoder_function(&msgs[i]);
}
}
// If no decoder function is found, skip this message
if (decoder_func) {
JsonValue *decoded = decoder_func(&msgs[i]);
if (decoded) {
// Copy all fields from decoded result to msg_result
for (JsonPair *pair = decoded->data.object; pair != NULL; pair = pair->next) {
// Create a copy of the value for the new object
JsonValue *value_copy = NULL;
switch (pair->value->type) {
case JSON_STRING:
value_copy = json_create_string(pair->value->data.string);
break;
case JSON_NUMBER:
value_copy = json_create_number(pair->value->data.number);
break;
case JSON_BOOL:
value_copy = json_create_bool(pair->value->data.boolean);
break;
case JSON_NULL:
value_copy = json_create_null();
break;
case JSON_ARRAY:
// For arrays, we need to copy each element
value_copy = json_create_array();
if (value_copy) {
for (size_t j = 0; j < pair->value->data.array.count; j++) {
JsonValue *elem = pair->value->data.array.items[j];
JsonValue *elem_copy = NULL;
if (elem->type == JSON_NUMBER) {
elem_copy = json_create_number(elem->data.number);
}
if (elem_copy) {
json_array_push(value_copy, elem_copy);
}
}
}
break;
default:
break;
}
if (value_copy) {
json_object_set(msg_result, pair->key, value_copy);
}
}
json_free(decoded);
}
}
json_object_set(results, msg_key, msg_result);
}
free(msgs);
free(has_marker);
return results;
}