| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Writing of vboot state into ACPI tables |
| * |
| * Copyright 2020 Google LLC |
| */ |
| |
| #define LOG_CATEGORY LOGC_VBOOT |
| |
| #include <common.h> |
| #include <bloblist.h> |
| #include <asm/cb_sysinfo.h> |
| #include <log.h> |
| #include <smbios.h> |
| #include <asm/intel_gnvs.h> |
| #include <cros/fwstore.h> |
| #include <cros/vboot.h> |
| |
| #include <vb2_internals_please_do_not_use.h> |
| |
| /** |
| * get_firmware_index() - Get the encoded firmware index |
| * |
| * @vbsd_fw_index: vboot firmware index |
| * @return associated index for using in ACPI |
| */ |
| static int get_firmware_index(struct vboot_info *vboot) |
| { |
| if (vboot_is_recovery(vboot)) |
| return BINF_RECOVERY; |
| else |
| return vboot_is_slot_a(vboot) ? BINF_RW_A : BINF_RW_B; |
| } |
| |
| int vboot_update_acpi(struct vboot_info *vboot, enum cros_fw_type_t fw_type) |
| { |
| struct vb2_context *ctx = vboot_get_ctx(vboot); |
| struct chromeos_acpi_gnvs *tab; |
| struct acpi_global_nvs *gnvs; |
| uint size; |
| ulong fmap_addr; |
| int main_fw; |
| uint chsw; |
| int ret; |
| |
| log_info("Updating ACPI tables\n"); |
| gnvs = bloblist_find(BLOBLISTT_ACPI_GNVS, sizeof(*gnvs)); |
| if (!gnvs) { |
| if (!vboot_from_cb(vboot)) |
| return log_msg_ret("bloblist", -ENOENT); |
| gnvs = vboot->sysinfo->acpi_gnvs; |
| if (!gnvs) |
| return log_msg_ret("gnvs", -ENOKEY); |
| } |
| tab = &gnvs->chromeos; |
| |
| /* Write VbSharedDataHeader to ACPI vdat for userspace access */ |
| vb2api_export_vbsd(ctx, tab->vdat); |
| |
| tab->boot_reason = BOOT_REASON_OTHER; |
| |
| tab->main_fw_type = get_firmware_index(vboot); |
| |
| if (vboot->ec_software_sync) { |
| int in_rw = 0; |
| |
| if (vb2ex_ec_running_rw(&in_rw)) { |
| log_err("Couldn't tell if the EC firmware is RW\n"); |
| return -EPROTO; |
| } |
| tab->activeec_fw = in_rw ? ACTIVE_ECFW_RW : ACTIVE_ECFW_RO; |
| } |
| |
| chsw = 0; |
| if (ctx->flags & VB2_CONTEXT_FORCE_RECOVERY_MODE) |
| chsw |= CHSW_RECOVERY_X86; |
| if (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) |
| chsw |= CHSW_DEVELOPER_SWITCH; |
| tab->switches = chsw; |
| |
| char hwid[VB2_GBB_HWID_MAX_SIZE]; |
| uint32_t hwid_size = min(sizeof(hwid), sizeof(tab->hwid)); |
| if (!vb2api_gbb_read_hwid(vboot_get_ctx(vboot), hwid, &hwid_size)) |
| memcpy(tab->hwid, hwid, hwid_size); |
| |
| size = min(ID_LEN, sizeof(tab->fwid)); |
| memcpy(tab->fwid, vboot->firmware_id, size); |
| |
| size = min(ID_LEN, sizeof(tab->frid)); |
| memcpy(tab->frid, vboot->readonly_firmware_id, size); |
| |
| if (fw_type != FIRMWARE_TYPE_AUTO_DETECT) |
| tab->main_fw_type = fw_type; // TODO: set this correctly |
| else if (main_fw == BINF_RECOVERY) |
| tab->main_fw_type = FIRMWARE_TYPE_RECOVERY; |
| else if (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) |
| tab->main_fw_type = FIRMWARE_TYPE_DEVELOPER; |
| else |
| tab->main_fw_type = FIRMWARE_TYPE_NORMAL; |
| |
| tab->recovery_reason = vb2api_get_recovery_reason(ctx); |
| |
| if (!vboot->fmap.readonly.fmap.length) { |
| log_err("No FMAP available\n"); |
| return -ENOTDIR; |
| } |
| ret = fwstore_entry_mmap(vboot->fwstore, &vboot->fmap.readonly.fmap, |
| &fmap_addr); |
| if (!ret) |
| tab->fmap_base = fmap_addr; |
| else |
| log_warning("FMAP address cannot be mapped (err=%d)\n", ret); |
| |
| if (IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE)) { |
| size = min(ID_LEN, sizeof(tab->fwid)); |
| ret = smbios_update_version(vboot->firmware_id); |
| if (ret) { |
| log_err("Unable to update SMBIOS type 0 version string\n"); |
| return log_msg_ret("smbios", ret); |
| } |
| } else if (vboot_from_cb(vboot)) { |
| void *smbios_start; |
| |
| smbios_start = (void *)(ulong)vboot->sysinfo->smbios_start; |
| if (!smbios_start) { |
| log_warning("SMBIOS table not provided\n"); |
| return log_msg_ret("tab", -ENOENT); |
| } |
| ret = smbios_update_version_full(smbios_start, |
| vboot->firmware_id); |
| if (ret) { |
| log_err("Unable to update SMBIOS type 0 version string\n"); |
| return log_msg_ret("cbsmbios", ret); |
| } |
| } |
| |
| return 0; |
| } |
| |