#if defined(CONFIG_PROC_FS) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(CONFIG_OF_AVM_DT) #include #endif union sbl_boot_status *get_sbl_boot_status(void) { #if defined(CONFIG_OF_AVM_DT) union sbl_boot_status *sbl_status; struct reserved_mem *rmem; rmem = fdt_get_reserved_mem_resource("avm_sbl_boot_string"); if (rmem) { sbl_status = (union sbl_boot_status *)phys_to_virt(rmem->base); return sbl_status; } #endif pr_info("[%s] No reserved memory for entry for avm_sbl_boot_string\n", __func__); return 0; } static struct proc_dir_entry *sblprocdir; static union sbl_boot_status *sbl_status; struct avm_tag_version get_avm_tag_version_from_string(char *version) { struct avm_tag_version ret = {0, 0, 0, 0, 0, 0}; char modified = 0; int valid; valid = sscanf(version, "%u.%u.%u.%u.%u-%c", &ret.v0, &ret.v1, &ret.v2, &ret.v3, &ret.v4, &modified); // 5 is the normal returnvalue, 6 is returned if there is a modified flag if ((valid != 5) && (valid != 6)) { memset(&ret, 0, sizeof(struct avm_tag_version)); return ret; } if (modified == 'M') ret.m = 1; return ret; } int get_sbl_boot_status_version(union sbl_boot_status *sbl_status) { int ret; if (sbl_status == NULL) { ret = 0; } else if (!strcmp(sbl_status->v1.magic_str, SBL_MAGIC_STRING_V1)) { ret = 1; } else if (!strcmp(sbl_status->v2.magic_str, SBL_MAGIC_STRING_V2)) { ret = sbl_status->v2.struct_version; } else { ret = 0; } return ret; } static unsigned int avm_tag_version_equal_num(struct avm_tag_version a, struct avm_tag_version b) { return (a.v0 == b.v0) && (a.v1 == b.v1) && (a.v2 == b.v2) && (a.v3 == b.v3) && (a.v4 == b.v4); } static unsigned int avm_tag_version_equal(struct avm_tag_version a, struct avm_tag_version b) { return avm_tag_version_equal_num(a, b) && (a.m == b.m); } unsigned int avm_tag_version_valid(struct avm_tag_version a) { struct avm_tag_version empty = {0, 0, 0, 0, 0, 0}; return !avm_tag_version_equal(a, empty); } static int is_sbl_boot_version_supported(int version, struct seq_file *seq) { switch (version) { case 0: pr_err("[%s] Magic mismatch for avm_sbl_boot_string\n", __func__); if (seq != NULL) { seq_puts(seq, "Magic mismatch"); } return 0; case 1: return 1; case 2: return 1; default: pr_err("[%s] Unknown version of %d for avm_sbl_boot_string\n", __func__, version); if (seq != NULL) { seq_puts(seq, "Unknown version"); } return 0; } } static void proc_tz_boot_index(struct seq_file *seq, void *priv __maybe_unused) { int version = get_sbl_boot_status_version(sbl_status); int tz_index; if (!is_sbl_boot_version_supported(version, seq)) { return; } else if (version == 1) { tz_index = sbl_status->v1.tz_boot_index; } else if (version == 2) { tz_index = sbl_status->v2.tz_boot_index; } seq_printf(seq, "%d\n", tz_index); } static void proc_eva_boot_index(struct seq_file *seq, void *priv __maybe_unused) { int version = get_sbl_boot_status_version(sbl_status); int eva_index; if (!is_sbl_boot_version_supported(version, seq)) { return; } else if (version == 1) { eva_index = sbl_status->v1.eva_boot_index; } else if (version == 2) { eva_index = sbl_status->v2.eva_boot_index; } seq_printf(seq, "%d\n", eva_index); } static void proc_tz_boot_ack(struct seq_file *seq, void *priv __maybe_unused) { int version = get_sbl_boot_status_version(sbl_status); int tz_ack; if (!is_sbl_boot_version_supported(version, seq)) { return; } else if (version == 1) { tz_ack = sbl_status->v1.tz_boot_successful; } else if (version == 2) { tz_ack = sbl_status->v2.tz_boot_successful; } seq_printf(seq, "%d\n", tz_ack); } static void proc_eva_boot_ack(struct seq_file *seq, void *priv __maybe_unused) { int version = get_sbl_boot_status_version(sbl_status); int eva_ack; if (!is_sbl_boot_version_supported(version, seq)) { return; } else if (version == 1) { eva_ack = sbl_status->v1.eva_boot_successful; } else if (version == 2) { eva_ack = sbl_status->v2.eva_boot_successful; } seq_printf(seq, "%d\n", eva_ack); } static int proc_write_eva_boot_ack(char *buffer, void *priv __maybe_unused) { int version = get_sbl_boot_status_version(sbl_status); int ack = 0; int ack_correct = 0; if (!is_sbl_boot_version_supported(version, NULL)) { return -EBADMSG; } sscanf(buffer, "%d", &ack); ack_correct = (ack == 1) || (ack == 0); if (!ack_correct) { return -EBADMSG; } if (version == 1) { sbl_status->v1.eva_boot_successful = ack; return 0; } else if (version == 2) { sbl_status->v2.eva_boot_successful = ack; return 0; } return -EBADMSG; } static int proc_write_tz_boot_ack(char *buffer, void *priv __maybe_unused) { int version = get_sbl_boot_status_version(sbl_status); int ack = 0; int ack_correct = 0; if (!is_sbl_boot_version_supported(version, NULL)) { return -EBADMSG; } sscanf(buffer, "%d", &ack); ack_correct = (ack == 1) || (ack == 0); if (!ack_correct) { return -EBADMSG; } if (version == 1) { sbl_status->v1.tz_boot_successful = ack; return 0; } else if (version == 2) { sbl_status->v2.tz_boot_successful = ack; return 0; } return -EBADMSG; } static int get_eva_verified(int eva_num, int version) { int verified; if (version == 1) { verified = sbl_status->v1.eva_verified[eva_num]; } else if (version == 2) { verified = sbl_status->v2.eva_verified[eva_num]; } return verified; } static void proc_eva0_verified(struct seq_file *seq, void *priv __maybe_unused) { int version; int verified; version = get_sbl_boot_status_version(sbl_status); if (!is_sbl_boot_version_supported(version, seq)) { return; } verified = get_eva_verified(0, version); seq_printf(seq, "%d\n", verified); } static void proc_eva1_verified(struct seq_file *seq, void *priv __maybe_unused) { int version; int verified; version = get_sbl_boot_status_version(sbl_status); if (!is_sbl_boot_version_supported(version, seq)) { return; } verified = get_eva_verified(1, version); seq_printf(seq, "%d\n", verified); } static int get_tz_verified(int tz_num, int version) { int verified; if (version == 1) { verified = sbl_status->v1.tz_verified[tz_num]; } else if (version == 2) { verified = sbl_status->v2.tz_verified[tz_num]; } return verified; } static void proc_tz0_verified(struct seq_file *seq, void *priv __maybe_unused) { int version; int verified; version = get_sbl_boot_status_version(sbl_status); if (!is_sbl_boot_version_supported(version, seq)) { return; } verified = get_tz_verified(0, version); seq_printf(seq, "%d\n", verified); } static void proc_tz1_verified(struct seq_file *seq, void *priv __maybe_unused) { int version; int verified; version = get_sbl_boot_status_version(sbl_status); if (!is_sbl_boot_version_supported(version, seq)) { return; } verified = get_tz_verified(1, version); seq_printf(seq, "%d\n", verified); } static void eva_version_to_seq(int eva_num, int version, struct seq_file *seq) { if (version == 1) { seq_printf(seq, "%d%s\n", sbl_status->v1.eva_version[eva_num], (sbl_status->v1.eva_modified[eva_num] ? "M" : "")); } else if (version == 2) { seq_printf(seq, "%s\n", sbl_status->v2.eva_version[eva_num]); } } static void proc_eva0_version(struct seq_file *seq, void *priv __maybe_unused) { int version; version = get_sbl_boot_status_version(sbl_status); if (!is_sbl_boot_version_supported(version, seq)) { return; } eva_version_to_seq(0, version, seq); } static void proc_eva1_version(struct seq_file *seq, void *priv __maybe_unused) { int version; version = get_sbl_boot_status_version(sbl_status); if (!is_sbl_boot_version_supported(version, seq)) { return; } eva_version_to_seq(1, version, seq); } static void tz_version_to_seq(int tz_num, int version, struct seq_file *seq) { if (version == 1) { seq_printf(seq, "%d%s\n", sbl_status->v1.tz_version[tz_num], (sbl_status->v1.tz_modified[tz_num] ? "M" : "")); } else if (version == 2) { seq_printf(seq, "%s\n", sbl_status->v2.tz_version[tz_num]); } } static void proc_tz0_version(struct seq_file *seq, void *priv __maybe_unused) { int version; version = get_sbl_boot_status_version(sbl_status); if (!is_sbl_boot_version_supported(version, seq)) { return; } tz_version_to_seq(0, version, seq); } static void proc_tz1_version(struct seq_file *seq, void *priv __maybe_unused) { int version; version = get_sbl_boot_status_version(sbl_status); if (!is_sbl_boot_version_supported(version, seq)) { return; } tz_version_to_seq(1, version, seq); } static void proc_sbl_version(struct seq_file *seq, void *priv __maybe_unused) { int version; version = get_sbl_boot_status_version(sbl_status); if (!is_sbl_boot_version_supported(version, seq)) { return; } if (version == 1) { seq_printf(seq, "%d%s\n", sbl_status->v1.sbl_version, (sbl_status->v1.sbl_modified ? "M" : "")); } else if (version == 2) { seq_printf(seq, "%s\n", sbl_status->v2.sbl_version); } } static void proc_struct_version(struct seq_file *seq, void *priv __maybe_unused) { int version; version = get_sbl_boot_status_version(sbl_status); if (!is_sbl_boot_version_supported(version, seq)) { return; } seq_printf(seq, "%d\n", version); } static void print_sbl_boot_status(int version) { if (version == 1) { pr_info("SBL Boot Info Version %d%s Boot TZ %d Boot Eva %d\n", sbl_status->v1.sbl_version, (sbl_status->v1.sbl_modified ? "M" : ""), sbl_status->v1.tz_boot_index, sbl_status->v1.eva_boot_index); if (sbl_status->v1.tz_verified[0]) { pr_info("TZ0 Version %d%s ", sbl_status->v1.tz_version[0], (sbl_status->v1.tz_modified[0] ? "M" : "")); } else { pr_info("TZ0 not verified\n"); } if (sbl_status->v1.tz_verified[1]) { pr_info("TZ1 Version %d%s\n", sbl_status->v1.tz_version[1], (sbl_status->v1.tz_modified[1] ? "M" : "")); } else { pr_info("TZ1 not verified\n"); } if (sbl_status->v1.eva_verified[0]) { pr_info("EVA0 Version %d%s\n", sbl_status->v1.eva_version[0], (sbl_status->v1.eva_modified[0] ? "M" : "")); } else { pr_info("EVA0 not verified\n"); } if (sbl_status->v1.eva_verified[1]) { pr_info("EVA1 Version %d%s\n", sbl_status->v1.eva_version[1], (sbl_status->v1.eva_modified[1] ? "M" : "")); } else { pr_info("EVA1 not verified\n"); } } else if (version == 2) { pr_info("SBL Boot Info Version %s Boot TZ %d Boot Eva %d\n", sbl_status->v2.sbl_version, sbl_status->v2.tz_boot_index, sbl_status->v2.eva_boot_index); if (sbl_status->v2.tz_verified[0]) { pr_info("TZ0 Version %s ", sbl_status->v2.tz_version[0]); } else { pr_info("TZ0 not verified\n"); } if (sbl_status->v2.tz_verified[1]) { pr_info("TZ1 Version %s\n", sbl_status->v2.tz_version[1]); } else { pr_info("TZ1 not verified\n"); } if (sbl_status->v2.eva_verified[0]) { pr_info("EVA0 Version %s\n", sbl_status->v2.eva_version[0]); } else { pr_info("EVA0 not verified\n"); } if (sbl_status->v2.eva_verified[1]) { pr_info("EVA1 Version %s\n", sbl_status->v2.eva_version[1]); } else { pr_info("EVA1 not verified\n"); } } } static __init int proc_sbl_boot_status(void) { int version; sbl_status = get_sbl_boot_status(); version = get_sbl_boot_status_version(sbl_status); if (!is_sbl_boot_version_supported(version, NULL)) { return 0; } print_sbl_boot_status(version); sblprocdir = proc_mkdir("avm/sbl_boot_info", NULL); if (sblprocdir == NULL) { return 0; } add_simple_proc_file("avm/sbl_boot_info/tz_boot_index", NULL, proc_tz_boot_index, NULL); add_simple_proc_file("avm/sbl_boot_info/eva_boot_index", NULL, proc_eva_boot_index, NULL); add_simple_proc_file("avm/sbl_boot_info/eva_boot_ack", proc_write_eva_boot_ack, proc_eva_boot_ack, NULL); add_simple_proc_file("avm/sbl_boot_info/tz_boot_ack", proc_write_tz_boot_ack, proc_tz_boot_ack, NULL); add_simple_proc_file("avm/sbl_boot_info/eva0_verified", NULL, proc_eva0_verified, NULL); add_simple_proc_file("avm/sbl_boot_info/eva1_verified", NULL, proc_eva1_verified, NULL); add_simple_proc_file("avm/sbl_boot_info/eva0_version", NULL, proc_eva0_version, NULL); add_simple_proc_file("avm/sbl_boot_info/eva1_version", NULL, proc_eva1_version, NULL); add_simple_proc_file("avm/sbl_boot_info/tz0_verified", NULL, proc_tz0_verified, NULL); add_simple_proc_file("avm/sbl_boot_info/tz1_verified", NULL, proc_tz1_verified, NULL); add_simple_proc_file("avm/sbl_boot_info/tz0_version", NULL, proc_tz0_version, NULL); add_simple_proc_file("avm/sbl_boot_info/tz1_version", NULL, proc_tz1_version, NULL); add_simple_proc_file("avm/sbl_boot_info/sbl_version", NULL, proc_sbl_version, NULL); add_simple_proc_file("avm/sbl_boot_info/struct_version", NULL, proc_struct_version, NULL); return 0; } late_initcall(proc_sbl_boot_status); #endif /* #if defined(CONFIG_PROC_FS) */