diff --git a/sys/conf/files.x86 b/sys/conf/files.x86 index 15781eea8fee..8bd58ab4d339 100644 --- a/sys/conf/files.x86 +++ b/sys/conf/files.x86 @@ -1,353 +1,354 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # # # This file contains all the x86 devices and such that are # common between i386 and amd64, but aren't applicable to # any other architecture we support. # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and # dependency lines other than the first are silently ignored. # atkbdmap.h optional atkbd_dflt_keymap \ compile-with "${KEYMAP} -L ${ATKBD_DFLT_KEYMAP} | ${KEYMAP_FIX} > ${.TARGET}" \ no-obj no-implicit-rule before-depend \ clean "atkbdmap.h" cddl/dev/fbt/x86/fbt_isa.c optional dtrace_fbt | dtraceall compile-with "${FBT_C}" cddl/dev/dtrace/x86/dis_tables.c optional dtrace_fbt | dtraceall compile-with "${DTRACE_C}" cddl/dev/dtrace/x86/instr_size.c optional dtrace_fbt | dtraceall compile-with "${DTRACE_C}" crypto/aesni/aesni.c optional aesni aesni_ghash.o optional aesni \ dependency "$S/crypto/aesni/aesni_ghash.c" \ compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${NO_WCAST_QUAL} -mmmx -msse -msse4 -maes -mpclmul ${.IMPSRC}" \ no-implicit-rule \ clean "aesni_ghash.o" aesni_ccm.o optional aesni \ dependency "$S/crypto/aesni/aesni_ccm.c" \ compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${NO_WCAST_QUAL} -mmmx -msse -msse4 -maes -mpclmul ${.IMPSRC}" \ no-implicit-rule \ clean "aesni_ccm.o" aesni_wrap.o optional aesni \ dependency "$S/crypto/aesni/aesni_wrap.c" \ compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${NO_WCAST_QUAL} -mmmx -msse -msse4 -maes ${.IMPSRC}" \ no-implicit-rule \ clean "aesni_wrap.o" intel_sha1.o optional aesni \ dependency "$S/crypto/aesni/intel_sha1.c" \ compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} -mmmx -msse -msse4 -msha ${.IMPSRC}" \ no-implicit-rule \ clean "intel_sha1.o" intel_sha256.o optional aesni \ dependency "$S/crypto/aesni/intel_sha256.c" \ compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} -mmmx -msse -msse4 -msha ${.IMPSRC}" \ no-implicit-rule \ clean "intel_sha256.o" crypto/openssl/ossl_x86.c optional ossl crypto/via/padlock.c optional padlock crypto/via/padlock_cipher.c optional padlock crypto/via/padlock_hash.c optional padlock dev/acpica/acpi_hpet.c optional acpi dev/acpica/acpi_if.m standard dev/acpica/acpi_pci.c optional acpi pci dev/acpica/acpi_pci_link.c optional acpi pci dev/acpica/acpi_pcib.c optional acpi pci dev/acpica/acpi_pcib_acpi.c optional acpi pci dev/acpica/acpi_pcib_pci.c optional acpi pci dev/acpica/acpi_pxm.c optional acpi dev/acpica/acpi_timer.c optional acpi dev/amdsbwd/amdsbwd.c optional amdsbwd dev/amdsmn/amdsmn.c optional amdsmn | amdtemp dev/amdtemp/amdtemp.c optional amdtemp dev/arcmsr/arcmsr.c optional arcmsr pci dev/asmc/asmc.c optional asmc isa dev/atkbdc/atkbd.c optional atkbd atkbdc dev/atkbdc/atkbd_atkbdc.c optional atkbd atkbdc dev/atkbdc/atkbdc.c optional atkbdc dev/atkbdc/atkbdc_isa.c optional atkbdc isa dev/atkbdc/atkbdc_subr.c optional atkbdc dev/atkbdc/psm.c optional psm atkbdc dev/atopcase/atopcase.c optional atopcase acpi hid spibus dev/atopcase/atopcase_acpi.c optional atopcase acpi hid spibus dev/bxe/bxe.c optional bxe pci dev/bxe/bxe_stats.c optional bxe pci dev/bxe/bxe_debug.c optional bxe pci dev/bxe/ecore_sp.c optional bxe pci dev/bxe/bxe_elink.c optional bxe pci dev/bxe/57710_init_values.c optional bxe pci dev/bxe/57711_init_values.c optional bxe pci dev/bxe/57712_init_values.c optional bxe pci dev/coretemp/coretemp.c optional coretemp dev/cpuctl/cpuctl.c optional cpuctl dev/dpms/dpms.c optional dpms dev/fb/fb.c optional fb | vga dev/fb/s3_pci.c optional s3pci dev/fb/vesa.c optional vga vesa dev/fb/vga.c optional vga dev/fdc/fdc.c optional fdc dev/fdc/fdc_acpi.c optional fdc dev/fdc/fdc_isa.c optional fdc isa dev/gpio/bytgpio.c optional bytgpio dev/gpio/chvgpio.c optional chvgpio dev/hpt27xx/hpt27xx_os_bsd.c optional hpt27xx dev/hpt27xx/hpt27xx_osm_bsd.c optional hpt27xx dev/hpt27xx/hpt27xx_config.c optional hpt27xx dev/hpt27xx/$M-elf.hpt27xx_lib.o optional hpt27xx dev/hptmv/entry.c optional hptmv dev/hptmv/mv.c optional hptmv dev/hptmv/gui_lib.c optional hptmv dev/hptmv/hptproc.c optional hptmv dev/hptmv/ioctl.c optional hptmv dev/hptmv/$M-elf.hptmvraid.o optional hptmv dev/hptnr/hptnr_os_bsd.c optional hptnr dev/hptnr/hptnr_osm_bsd.c optional hptnr dev/hptnr/hptnr_config.c optional hptnr dev/hptnr/$M-elf.hptnr_lib.o optional hptnr dev/hptrr/hptrr_os_bsd.c optional hptrr dev/hptrr/hptrr_osm_bsd.c optional hptrr dev/hptrr/hptrr_config.c optional hptrr dev/hptrr/$M-elf.hptrr_lib.o optional hptrr dev/hwpmc/hwpmc_amd.c optional hwpmc dev/hwpmc/hwpmc_intel.c optional hwpmc dev/hwpmc/hwpmc_core.c optional hwpmc dev/hwpmc/hwpmc_uncore.c optional hwpmc dev/hwpmc/hwpmc_tsc.c optional hwpmc dev/hwpmc/hwpmc_x86.c optional hwpmc dev/hyperv/hvsock/hv_sock.c optional hyperv dev/hyperv/input/hv_hid.c optional hyperv hvhid dev/hyperv/input/hv_kbd.c optional hyperv dev/hyperv/input/hv_kbdc.c optional hyperv dev/hyperv/pcib/vmbus_pcib.c optional hyperv pci dev/hyperv/netvsc/hn_nvs.c optional hyperv dev/hyperv/netvsc/hn_rndis.c optional hyperv dev/hyperv/netvsc/if_hn.c optional hyperv dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c optional hyperv dev/hyperv/utilities/hv_kvp.c optional hyperv dev/hyperv/utilities/hv_snapshot.c optional hyperv dev/hyperv/utilities/vmbus_heartbeat.c optional hyperv dev/hyperv/utilities/vmbus_ic.c optional hyperv dev/hyperv/utilities/vmbus_shutdown.c optional hyperv dev/hyperv/utilities/vmbus_timesync.c optional hyperv dev/hyperv/vmbus/hyperv.c optional hyperv dev/hyperv/vmbus/x86/hyperv_x86.c optional hyperv dev/hyperv/vmbus/x86/vmbus_x86.c optional hyperv dev/hyperv/vmbus/hyperv_busdma.c optional hyperv dev/hyperv/vmbus/vmbus.c optional hyperv pci dev/hyperv/vmbus/vmbus_br.c optional hyperv dev/hyperv/vmbus/vmbus_chan.c optional hyperv dev/hyperv/vmbus/vmbus_et.c optional hyperv dev/hyperv/vmbus/vmbus_if.m optional hyperv dev/hyperv/vmbus/vmbus_res.c optional hyperv dev/hyperv/vmbus/vmbus_xact.c optional hyperv dev/ichwd/ichwd.c optional ichwd dev/imcsmb/imcsmb.c optional imcsmb dev/imcsmb/imcsmb_pci.c optional imcsmb pci dev/intel/pchtherm.c optional pchtherm dev/intel/spi.c optional intelspi dev/intel/spi_pci.c optional intelspi pci dev/intel/spi_acpi.c optional intelspi acpi dev/io/iodev.c optional io dev/iommu/busdma_iommu.c optional acpi iommu pci dev/iommu/iommu_gas.c optional acpi iommu pci dev/ipmi/ipmi.c optional ipmi dev/ipmi/ipmi_acpi.c optional ipmi acpi dev/ipmi/ipmi_isa.c optional ipmi isa dev/ipmi/ipmi_bt.c optional ipmi dev/ipmi/ipmi_kcs.c optional ipmi dev/ipmi/ipmi_smic.c optional ipmi dev/ipmi/ipmi_smbus.c optional ipmi smbus dev/ipmi/ipmi_smbios.c optional ipmi dev/ipmi/ipmi_ssif.c optional ipmi smbus dev/ipmi/ipmi_pci.c optional ipmi pci dev/isci/isci.c optional isci \ compile-with "${NORMAL_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" dev/isci/isci_controller.c optional isci dev/isci/isci_domain.c optional isci dev/isci/isci_interrupt.c optional isci dev/isci/isci_io_request.c optional isci dev/isci/isci_logger.c optional isci dev/isci/isci_oem_parameters.c optional isci dev/isci/isci_remote_device.c optional isci dev/isci/isci_sysctl.c optional isci dev/isci/isci_task_request.c optional isci dev/isci/isci_timer.c optional isci dev/isci/scil/sati.c optional isci dev/isci/scil/sati_abort_task_set.c optional isci dev/isci/scil/sati_atapi.c optional isci dev/isci/scil/sati_device.c optional isci dev/isci/scil/sati_inquiry.c optional isci dev/isci/scil/sati_log_sense.c optional isci dev/isci/scil/sati_lun_reset.c optional isci dev/isci/scil/sati_mode_pages.c optional isci dev/isci/scil/sati_mode_select.c optional isci \ compile-with "${NORMAL_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" dev/isci/scil/sati_mode_sense.c optional isci dev/isci/scil/sati_mode_sense_10.c optional isci dev/isci/scil/sati_mode_sense_6.c optional isci dev/isci/scil/sati_move.c optional isci dev/isci/scil/sati_passthrough.c optional isci \ compile-with "${NORMAL_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" dev/isci/scil/sati_read.c optional isci dev/isci/scil/sati_read_buffer.c optional isci dev/isci/scil/sati_read_capacity.c optional isci dev/isci/scil/sati_reassign_blocks.c optional isci \ compile-with "${NORMAL_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" dev/isci/scil/sati_report_luns.c optional isci dev/isci/scil/sati_request_sense.c optional isci dev/isci/scil/sati_start_stop_unit.c optional isci dev/isci/scil/sati_synchronize_cache.c optional isci dev/isci/scil/sati_test_unit_ready.c optional isci dev/isci/scil/sati_unmap.c optional isci \ compile-with "${NORMAL_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" dev/isci/scil/sati_util.c optional isci dev/isci/scil/sati_verify.c optional isci dev/isci/scil/sati_write.c optional isci dev/isci/scil/sati_write_and_verify.c optional isci dev/isci/scil/sati_write_buffer.c optional isci dev/isci/scil/sati_write_long.c optional isci dev/isci/scil/sci_abstract_list.c optional isci dev/isci/scil/sci_base_controller.c optional isci dev/isci/scil/sci_base_domain.c optional isci dev/isci/scil/sci_base_iterator.c optional isci dev/isci/scil/sci_base_library.c optional isci dev/isci/scil/sci_base_logger.c optional isci dev/isci/scil/sci_base_memory_descriptor_list.c optional isci dev/isci/scil/sci_base_memory_descriptor_list_decorator.c optional isci dev/isci/scil/sci_base_object.c optional isci dev/isci/scil/sci_base_observer.c optional isci dev/isci/scil/sci_base_phy.c optional isci dev/isci/scil/sci_base_port.c optional isci dev/isci/scil/sci_base_remote_device.c optional isci dev/isci/scil/sci_base_request.c optional isci dev/isci/scil/sci_base_state_machine.c optional isci dev/isci/scil/sci_base_state_machine_logger.c optional isci dev/isci/scil/sci_base_state_machine_observer.c optional isci dev/isci/scil/sci_base_subject.c optional isci dev/isci/scil/sci_util.c optional isci dev/isci/scil/scic_sds_controller.c optional isci \ compile-with "${NORMAL_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" dev/isci/scil/scic_sds_library.c optional isci dev/isci/scil/scic_sds_pci.c optional isci dev/isci/scil/scic_sds_phy.c optional isci \ compile-with "${NORMAL_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" dev/isci/scil/scic_sds_port.c optional isci dev/isci/scil/scic_sds_port_configuration_agent.c optional isci dev/isci/scil/scic_sds_remote_device.c optional isci dev/isci/scil/scic_sds_remote_node_context.c optional isci dev/isci/scil/scic_sds_remote_node_table.c optional isci dev/isci/scil/scic_sds_request.c optional isci \ compile-with "${NORMAL_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" dev/isci/scil/scic_sds_sgpio.c optional isci dev/isci/scil/scic_sds_smp_remote_device.c optional isci dev/isci/scil/scic_sds_smp_request.c optional isci \ compile-with "${NORMAL_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" dev/isci/scil/scic_sds_ssp_request.c optional isci dev/isci/scil/scic_sds_stp_packet_request.c optional isci dev/isci/scil/scic_sds_stp_remote_device.c optional isci dev/isci/scil/scic_sds_stp_request.c optional isci \ compile-with "${NORMAL_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" dev/isci/scil/scic_sds_unsolicited_frame_control.c optional isci dev/isci/scil/scif_sas_controller.c optional isci \ compile-with "${NORMAL_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" dev/isci/scil/scif_sas_controller_state_handlers.c optional isci dev/isci/scil/scif_sas_controller_states.c optional isci dev/isci/scil/scif_sas_domain.c optional isci dev/isci/scil/scif_sas_domain_state_handlers.c optional isci \ compile-with "${NORMAL_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" dev/isci/scil/scif_sas_domain_states.c optional isci dev/isci/scil/scif_sas_high_priority_request_queue.c optional isci dev/isci/scil/scif_sas_internal_io_request.c optional isci dev/isci/scil/scif_sas_io_request.c optional isci dev/isci/scil/scif_sas_io_request_state_handlers.c optional isci dev/isci/scil/scif_sas_io_request_states.c optional isci dev/isci/scil/scif_sas_library.c optional isci dev/isci/scil/scif_sas_remote_device.c optional isci dev/isci/scil/scif_sas_remote_device_ready_substate_handlers.c optional isci dev/isci/scil/scif_sas_remote_device_ready_substates.c optional isci \ compile-with "${NORMAL_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" dev/isci/scil/scif_sas_remote_device_starting_substate_handlers.c optional isci dev/isci/scil/scif_sas_remote_device_starting_substates.c optional isci dev/isci/scil/scif_sas_remote_device_state_handlers.c optional isci dev/isci/scil/scif_sas_remote_device_states.c optional isci dev/isci/scil/scif_sas_request.c optional isci dev/isci/scil/scif_sas_smp_activity_clear_affiliation.c optional isci dev/isci/scil/scif_sas_smp_io_request.c optional isci dev/isci/scil/scif_sas_smp_phy.c optional isci dev/isci/scil/scif_sas_smp_remote_device.c optional isci \ compile-with "${NORMAL_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" dev/isci/scil/scif_sas_stp_io_request.c optional isci dev/isci/scil/scif_sas_stp_remote_device.c optional isci dev/isci/scil/scif_sas_stp_task_request.c optional isci dev/isci/scil/scif_sas_task_request.c optional isci dev/isci/scil/scif_sas_task_request_state_handlers.c optional isci dev/isci/scil/scif_sas_task_request_states.c optional isci dev/isci/scil/scif_sas_timer.c optional isci dev/itwd/itwd.c optional itwd dev/kvm_clock/kvm_clock.c optional kvm_clock dev/mana/gdma_main.c optional mana dev/mana/mana_en.c optional mana dev/mana/mana_sysctl.c optional mana dev/mana/shm_channel.c optional mana dev/mana/hw_channel.c optional mana dev/mana/gdma_util.c optional mana dev/qat_c2xxx/qat.c optional qat_c2xxx dev/qat_c2xxx/qat_ae.c optional qat_c2xxx dev/qat_c2xxx/qat_c2xxx.c optional qat_c2xxx dev/qat_c2xxx/qat_hw15.c optional qat_c2xxx dev/smbios/smbios_subr.c standard libkern/strcmp.c standard libkern/strncmp.c standard libkern/x86/crc32_sse42.c standard # # x86 shared code between IA32 and AMD64 architectures # x86/acpica/OsdEnvironment.c optional acpi x86/acpica/acpi_apm.c optional acpi x86/acpica/srat.c optional acpi x86/bios/vpd.c optional vpd x86/cpufreq/est.c optional cpufreq x86/cpufreq/hwpstate_amd.c optional cpufreq x86/cpufreq/hwpstate_intel.c optional cpufreq x86/cpufreq/p4tcc.c optional cpufreq x86/cpufreq/powernow.c optional cpufreq x86/iommu/intel_ctx.c optional acpi iommu pci x86/iommu/intel_drv.c optional acpi iommu pci x86/iommu/intel_fault.c optional acpi iommu pci x86/iommu/intel_idpgtbl.c optional acpi iommu pci x86/iommu/intel_intrmap.c optional acpi iommu pci x86/iommu/intel_qi.c optional acpi iommu pci x86/iommu/intel_quirks.c optional acpi iommu pci x86/iommu/intel_utils.c optional acpi iommu pci x86/isa/atrtc.c standard x86/isa/clock.c standard x86/isa/isa.c optional isa x86/isa/isa_dma.c optional isa x86/isa/nmi.c standard x86/isa/orm.c optional isa x86/pci/pci_bus.c optional pci x86/pci/qpi.c optional pci x86/x86/autoconf.c standard x86/x86/bus_machdep.c standard x86/x86/busdma_bounce.c standard x86/x86/busdma_machdep.c standard x86/x86/cpu_machdep.c standard x86/x86/dbreg.c optional ddb | gdb x86/x86/dump_machdep.c standard x86/x86/fdt_machdep.c optional fdt x86/x86/identcpu.c standard x86/x86/intr_machdep.c standard x86/x86/legacy.c standard x86/x86/mca.c standard x86/x86/x86_mem.c optional mem x86/x86/mp_x86.c optional smp x86/x86/nexus.c standard x86/x86/pvclock.c optional kvm_clock | xenhvm x86/x86/stack_machdep.c optional ddb | stack x86/x86/tsc.c standard x86/x86/ucode.c standard +x86/x86/ucode_subr.c standard x86/x86/delay.c standard x86/xen/hvm.c optional xenhvm x86/xen/xen_apic.c optional xenhvm smp x86/xen/xen_arch_intr.c optional xenhvm diff --git a/sys/x86/include/ucode.h b/sys/x86/include/ucode.h index e97d41c89ed0..0338d48a0832 100644 --- a/sys/x86/include/ucode.h +++ b/sys/x86/include/ucode.h @@ -1,66 +1,77 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018 The FreeBSD Foundation * * This software was developed by Mark Johnston under sponsorship from * the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _MACHINE_UCODE_H_ #define _MACHINE_UCODE_H_ +#ifdef _KERNEL +#include +#else +#include +#endif + struct ucode_intel_header { uint32_t header_version; int32_t update_revision; uint32_t dat; uint32_t processor_signature; uint32_t checksum; uint32_t loader_revision; uint32_t processor_flags; #define UCODE_INTEL_DEFAULT_DATA_SIZE 2000 uint32_t data_size; uint32_t total_size; uint32_t reserved[3]; }; struct ucode_intel_extsig_table { uint32_t signature_count; uint32_t signature_table_checksum; uint32_t reserved[3]; struct ucode_intel_extsig { uint32_t processor_signature; uint32_t processor_flags; uint32_t checksum; } entries[0]; }; +const void *ucode_amd_find(const char *path, uint32_t signature, + uint32_t revision, const uint8_t *fw_data, size_t fw_size, + size_t *selected_sizep); int ucode_intel_load(const void *data, bool unsafe, uint64_t *nrevp, uint64_t *orevp); +int ucode_amd_load(const void *data, bool unsafe, + uint64_t *nrevp, uint64_t *orevp); size_t ucode_load_bsp(uintptr_t free); void ucode_load_ap(int cpu); void ucode_reload(void); void * ucode_update(void *data); #endif /* _MACHINE_UCODE_H_ */ diff --git a/sys/x86/x86/ucode.c b/sys/x86/x86/ucode.c index 8e9f8e113c40..923d9e31b44e 100644 --- a/sys/x86/x86/ucode.c +++ b/sys/x86/x86/ucode.c @@ -1,399 +1,454 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018 The FreeBSD Foundation * * This software was developed by Mark Johnston under sponsorship from * the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const void *ucode_intel_match(const uint8_t *data, size_t *len); static int ucode_intel_verify(const struct ucode_intel_header *hdr, size_t resid); +static const void *ucode_amd_match(const uint8_t *data, size_t *len); + static struct ucode_ops { const char *vendor; int (*load)(const void *, bool, uint64_t *, uint64_t *); const void *(*match)(const uint8_t *, size_t *); } loaders[] = { { .vendor = INTEL_VENDOR_ID, .load = ucode_intel_load, .match = ucode_intel_match, }, + { + .vendor = AMD_VENDOR_ID, + .load = ucode_amd_load, + .match = ucode_amd_match, + }, }; /* Selected microcode update data. */ static const void *early_ucode_data; static const void *ucode_data; static struct ucode_ops *ucode_loader; /* Variables used for reporting success or failure. */ enum { NO_ERROR, NO_MATCH, VERIFICATION_FAILED, } ucode_error = NO_ERROR; static uint64_t ucode_nrev, ucode_orev; static void log_msg(void *arg __unused) { if (ucode_nrev != 0) { printf("CPU microcode: updated from %#jx to %#jx\n", (uintmax_t)ucode_orev, (uintmax_t)ucode_nrev); return; } switch (ucode_error) { case NO_MATCH: printf("CPU microcode: no matching update found\n"); break; case VERIFICATION_FAILED: printf("CPU microcode: microcode verification failed\n"); break; default: break; } } SYSINIT(ucode_log, SI_SUB_CPU, SI_ORDER_FIRST, log_msg, NULL); int ucode_intel_load(const void *data, bool unsafe, uint64_t *nrevp, uint64_t *orevp) { uint64_t nrev, orev; uint32_t cpuid[4]; orev = rdmsr(MSR_BIOS_SIGN) >> 32; /* * Perform update. Flush caches first to work around seemingly * undocumented errata applying to some Broadwell CPUs. */ wbinvd(); if (unsafe) wrmsr_safe(MSR_BIOS_UPDT_TRIG, (uint64_t)(uintptr_t)data); else wrmsr(MSR_BIOS_UPDT_TRIG, (uint64_t)(uintptr_t)data); wrmsr(MSR_BIOS_SIGN, 0); /* * Serialize instruction flow. */ do_cpuid(0, cpuid); /* * Verify that the microcode revision changed. */ nrev = rdmsr(MSR_BIOS_SIGN) >> 32; if (nrevp != NULL) *nrevp = nrev; if (orevp != NULL) *orevp = orev; if (nrev <= orev) return (EEXIST); return (0); } static int ucode_intel_verify(const struct ucode_intel_header *hdr, size_t resid) { const uint32_t *data; uint32_t cksum, size; int i; if (resid < sizeof(struct ucode_intel_header)) return (1); size = hdr->total_size; if (size == 0) size = UCODE_INTEL_DEFAULT_DATA_SIZE + sizeof(struct ucode_intel_header); if (hdr->header_version != 1) return (1); if (size % 16 != 0) return (1); if (resid < size) return (1); cksum = 0; data = (const uint32_t *)hdr; for (i = 0; i < size / sizeof(uint32_t); i++) cksum += data[i]; if (cksum != 0) return (1); return (0); } static const void * ucode_intel_match(const uint8_t *data, size_t *len) { const struct ucode_intel_header *hdr; const struct ucode_intel_extsig_table *table; const struct ucode_intel_extsig *entry; uint64_t platformid; size_t resid; uint32_t data_size, flags, regs[4], sig, total_size; int i; do_cpuid(1, regs); sig = regs[0]; platformid = rdmsr(MSR_IA32_PLATFORM_ID); flags = 1 << ((platformid >> 50) & 0x7); for (resid = *len; resid > 0; data += total_size, resid -= total_size) { hdr = (const struct ucode_intel_header *)data; if (ucode_intel_verify(hdr, resid) != 0) { ucode_error = VERIFICATION_FAILED; break; } data_size = hdr->data_size; total_size = hdr->total_size; if (data_size == 0) data_size = UCODE_INTEL_DEFAULT_DATA_SIZE; if (total_size == 0) total_size = UCODE_INTEL_DEFAULT_DATA_SIZE + sizeof(struct ucode_intel_header); if (data_size > total_size + sizeof(struct ucode_intel_header)) table = (const struct ucode_intel_extsig_table *) ((const uint8_t *)(hdr + 1) + data_size); else table = NULL; if (hdr->processor_signature == sig) { if ((hdr->processor_flags & flags) != 0) { *len = data_size; return (hdr + 1); } } else if (table != NULL) { for (i = 0; i < table->signature_count; i++) { entry = &table->entries[i]; if (entry->processor_signature == sig && (entry->processor_flags & flags) != 0) { *len = data_size; return (hdr + 1); } } } } return (NULL); } +int +ucode_amd_load(const void *data, bool unsafe, uint64_t *nrevp, uint64_t *orevp) +{ + uint64_t nrev, orev; + uint32_t cpuid[4]; + + orev = rdmsr(MSR_BIOS_SIGN); + + /* + * Perform update. + */ + if (unsafe) + wrmsr_safe(MSR_K8_UCODE_UPDATE, (uint64_t)(uintptr_t)data); + else + wrmsr(MSR_K8_UCODE_UPDATE, (uint64_t)(uintptr_t)data); + + /* + * Serialize instruction flow. + */ + do_cpuid(0, cpuid); + + /* + * Verify that the microcode revision changed. + */ + nrev = rdmsr(MSR_BIOS_SIGN); + if (nrevp != NULL) + *nrevp = nrev; + if (orevp != NULL) + *orevp = orev; + if (nrev <= orev) + return (EEXIST); + return (0); + +} + +static const void * +ucode_amd_match(const uint8_t *data, size_t *len) +{ + uint32_t signature, revision; + uint32_t regs[4]; + + do_cpuid(1, regs); + signature = regs[0]; + revision = rdmsr(MSR_BIOS_SIGN); + + return (ucode_amd_find("loader blob", signature, revision, data, *len, len)); +} + /* * Release any memory backing unused microcode blobs back to the system. * We copy the selected update and free the entire microcode file. */ static void ucode_release(void *arg __unused) { char *name, *type; caddr_t file; int release; if (early_ucode_data == NULL) return; release = 1; TUNABLE_INT_FETCH("debug.ucode.release", &release); if (!release) return; restart: file = 0; for (;;) { file = preload_search_next_name(file); if (file == 0) break; type = (char *)preload_search_info(file, MODINFO_TYPE); if (type == NULL || strcmp(type, "cpu_microcode") != 0) continue; name = preload_search_info(file, MODINFO_NAME); preload_delete_name(name); goto restart; } } SYSINIT(ucode_release, SI_SUB_SMP + 1, SI_ORDER_ANY, ucode_release, NULL); void ucode_load_ap(int cpu) { #ifdef SMP KASSERT(cpu_info[cpu_apic_ids[cpu]].cpu_present, ("cpu %d not present", cpu)); if (cpu_info[cpu_apic_ids[cpu]].cpu_hyperthread) return; #endif if (ucode_data != NULL) (void)ucode_loader->load(ucode_data, false, NULL, NULL); } static void * map_ucode(uintptr_t free, size_t len) { #ifdef __i386__ uintptr_t va; for (va = free; va < free + len; va += PAGE_SIZE) pmap_kenter(va, (vm_paddr_t)va); #else (void)len; #endif return ((void *)free); } static void unmap_ucode(uintptr_t free, size_t len) { #ifdef __i386__ uintptr_t va; for (va = free; va < free + len; va += PAGE_SIZE) pmap_kremove(va); #else (void)free; (void)len; #endif } /* * Search for an applicable microcode update, and load it. APs will load the * selected update once they come online. * * "free" is the address of the next free physical page. If a microcode update * is selected, it will be copied to this region prior to loading in order to * satisfy alignment requirements. */ size_t ucode_load_bsp(uintptr_t free) { union { uint32_t regs[4]; char vendor[13]; } cpuid; const uint8_t *fileaddr, *match; uint8_t *addr; char *type; uint64_t nrev, orev; caddr_t file; size_t i, len; int error; KASSERT(free % PAGE_SIZE == 0, ("unaligned boundary %p", (void *)free)); do_cpuid(0, cpuid.regs); cpuid.regs[0] = cpuid.regs[1]; cpuid.regs[1] = cpuid.regs[3]; cpuid.vendor[12] = '\0'; for (i = 0; i < nitems(loaders); i++) if (strcmp(cpuid.vendor, loaders[i].vendor) == 0) { ucode_loader = &loaders[i]; break; } if (ucode_loader == NULL) return (0); file = 0; fileaddr = match = NULL; for (;;) { file = preload_search_next_name(file); if (file == 0) break; type = (char *)preload_search_info(file, MODINFO_TYPE); if (type == NULL || strcmp(type, "cpu_microcode") != 0) continue; fileaddr = preload_fetch_addr(file); len = preload_fetch_size(file); match = ucode_loader->match(fileaddr, &len); if (match != NULL) { addr = map_ucode(free, len); /* We can't use memcpy() before ifunc resolution. */ memcpy_early(addr, match, len); match = addr; error = ucode_loader->load(match, false, &nrev, &orev); if (error == 0) { ucode_data = early_ucode_data = match; ucode_nrev = nrev; ucode_orev = orev; return (len); } unmap_ucode(free, len); } } if (fileaddr != NULL && ucode_error == NO_ERROR) ucode_error = NO_MATCH; return (0); } /* * Reload microcode following an ACPI resume. */ void ucode_reload(void) { ucode_load_ap(PCPU_GET(cpuid)); } /* * Replace an existing microcode update. */ void * ucode_update(void *newdata) { newdata = (void *)atomic_swap_ptr((void *)&ucode_data, (uintptr_t)newdata); if (newdata == early_ucode_data) newdata = NULL; return (newdata); } diff --git a/usr.sbin/cpucontrol/amd10h.c b/sys/x86/x86/ucode_subr.c similarity index 64% copy from usr.sbin/cpucontrol/amd10h.c copy to sys/x86/x86/ucode_subr.c index aceb6bfa2ba5..9e128ad2bf04 100644 --- a/usr.sbin/cpucontrol/amd10h.c +++ b/sys/x86/x86/ucode_subr.c @@ -1,288 +1,239 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2006, 2008 Stanislav Sedov . + * All rights reserved. * Copyright (c) 2012 Andriy Gapon . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include -#include -#include -#include -#include +#include +#include -#include -#include +#include -#include -#include -#include -#include -#include -#include +#ifndef _KERNEL #include #include "cpucontrol.h" -#include "amd.h" +#endif -int -amd10h_probe(int fd) -{ - char vendor[13]; - cpuctl_cpuid_args_t idargs; - uint32_t family; - uint32_t signature; - int error; - idargs.level = 0; - error = ioctl(fd, CPUCTL_CPUID, &idargs); - if (error < 0) { - WARN(0, "ioctl()"); - return (1); +#ifdef _KERNEL +#define WARNX(level, ...) \ + if (bootverbose) { \ + printf(__VA_ARGS__); \ + printf("\n"); \ } - ((uint32_t *)vendor)[0] = idargs.data[1]; - ((uint32_t *)vendor)[1] = idargs.data[3]; - ((uint32_t *)vendor)[2] = idargs.data[2]; - vendor[12] = '\0'; - if (strncmp(vendor, AMD_VENDOR_ID, sizeof(AMD_VENDOR_ID)) != 0) - return (1); +#endif - idargs.level = 1; - error = ioctl(fd, CPUCTL_CPUID, &idargs); - if (error < 0) { - WARN(0, "ioctl()"); - return (1); - } - signature = idargs.data[0]; - family = ((signature >> 8) & 0x0f) + ((signature >> 20) & 0xff); - if (family < 0x10) - return (1); - return (0); -} +/* + * AMD family 10h and later. + */ +typedef struct amd_10h_fw_header { + uint32_t data_code; + uint32_t patch_id; + uint16_t mc_patch_data_id; + uint8_t mc_patch_data_len; + uint8_t init_flag; + uint32_t mc_patch_data_checksum; + uint32_t nb_dev_id; + uint32_t sb_dev_id; + uint16_t processor_rev_id; + uint8_t nb_rev_id; + uint8_t sb_rev_id; + uint8_t bios_api_rev; + uint8_t reserved1[3]; + uint32_t match_reg[8]; +} amd_10h_fw_header_t; + +typedef struct equiv_cpu_entry { + uint32_t installed_cpu; + uint32_t fixed_errata_mask; + uint32_t fixed_errata_compare; + uint16_t equiv_cpu; + uint16_t res; +} equiv_cpu_entry_t; + +typedef struct section_header { + uint32_t type; + uint32_t size; +} section_header_t; + +typedef struct container_header { + uint32_t magic; +} container_header_t; + +#define AMD_10H_MAGIC 0x414d44 +#define AMD_10H_EQUIV_TABLE_TYPE 0 +#define AMD_10H_uCODE_TYPE 1 /* * NB: the format of microcode update files is not documented by AMD. * It has been reverse engineered from studying Coreboot, illumos and Linux * source code. */ -void -amd10h_update(const struct ucode_update_params *params) +const void * +ucode_amd_find(const char *path, uint32_t signature, uint32_t revision, + const uint8_t *fw_data, size_t fw_size, size_t *selected_sizep) { - cpuctl_cpuid_args_t idargs; - cpuctl_msr_args_t msrargs; - cpuctl_update_args_t args; const amd_10h_fw_header_t *fw_header; const amd_10h_fw_header_t *selected_fw; const equiv_cpu_entry_t *equiv_cpu_table; const section_header_t *section_header; const container_header_t *container_header; - const uint8_t *fw_data; - const uint8_t *fw_image; - const char *dev, *path; - size_t fw_size; size_t selected_size; - uint32_t revision; - uint32_t new_rev; - uint32_t signature; uint16_t equiv_id; - int devfd; - unsigned int i; - int error; - - dev = params->dev_path; - path = params->fw_path; - devfd = params->devfd; - fw_image = params->fwimage; - fw_size = params->fwsize; - - assert(path); - assert(dev); - - idargs.level = 1; - error = ioctl(devfd, CPUCTL_CPUID, &idargs); - if (error < 0) { - WARN(0, "ioctl()"); - goto done; - } - signature = idargs.data[0]; - - msrargs.msr = MSR_BIOS_SIGN; - error = ioctl(devfd, CPUCTL_RDMSR, &msrargs); - if (error < 0) { - WARN(0, "ioctl(%s)", dev); - goto done; - } - revision = (uint32_t)msrargs.data; + int i; WARNX(1, "found cpu family %#x model %#x " "stepping %#x extfamily %#x extmodel %#x.", ((signature >> 8) & 0x0f) + ((signature >> 20) & 0xff), (signature >> 4) & 0x0f, (signature >> 0) & 0x0f, (signature >> 20) & 0xff, (signature >> 16) & 0x0f); WARNX(1, "microcode revision %#x", revision); - /* - * Open the firmware file. - */ +nextfile: WARNX(1, "checking %s for update.", path); + WARNX(3, "processing next container file"); if (fw_size < (sizeof(*container_header) + sizeof(*section_header))) { WARNX(2, "file too short: %s", path); - goto done; + return (NULL); } - /* - * mmap the whole image. - */ - fw_data = fw_image; container_header = (const container_header_t *)fw_data; if (container_header->magic != AMD_10H_MAGIC) { WARNX(2, "%s is not a valid amd firmware: bad magic", path); - goto done; + return (NULL); } fw_data += sizeof(*container_header); fw_size -= sizeof(*container_header); section_header = (const section_header_t *)fw_data; if (section_header->type != AMD_10H_EQUIV_TABLE_TYPE) { WARNX(2, "%s is not a valid amd firmware: " "first section is not CPU equivalence table", path); - goto done; + return (NULL); } if (section_header->size == 0) { WARNX(2, "%s is not a valid amd firmware: " "first section is empty", path); - goto done; + return (NULL); } fw_data += sizeof(*section_header); fw_size -= sizeof(*section_header); if (section_header->size > fw_size) { WARNX(2, "%s is not a valid amd firmware: " "file is truncated", path); - goto done; + return (NULL); } if (section_header->size < sizeof(*equiv_cpu_table)) { WARNX(2, "%s is not a valid amd firmware: " "first section is too short", path); - goto done; + return (NULL); } equiv_cpu_table = (const equiv_cpu_entry_t *)fw_data; fw_data += section_header->size; fw_size -= section_header->size; equiv_id = 0; for (i = 0; equiv_cpu_table[i].installed_cpu != 0; i++) { + WARNX(3, "signature 0x%x i %d installed_cpu 0x%x equiv 0x%x", + signature, i, equiv_cpu_table[i].installed_cpu, + equiv_cpu_table[i].equiv_cpu); if (signature == equiv_cpu_table[i].installed_cpu) { equiv_id = equiv_cpu_table[i].equiv_cpu; WARNX(3, "equiv_id: %x, signature %8x," " equiv_cpu_table[%d] %8x", equiv_id, signature, i, equiv_cpu_table[i].installed_cpu); break; } } if (equiv_id == 0) { WARNX(2, "CPU is not found in the equivalence table"); - goto done; } - selected_fw = NULL; - selected_size = 0; while (fw_size >= sizeof(*section_header)) { section_header = (const section_header_t *)fw_data; + if (section_header->type == AMD_10H_MAGIC) { + WARNX(2, "%s next section is actually a new container", + path); + if (selected_fw != NULL) + goto found; + else + goto nextfile; + } fw_data += sizeof(*section_header); fw_size -= sizeof(*section_header); if (section_header->type != AMD_10H_uCODE_TYPE) { WARNX(2, "%s is not a valid amd firmware: " "section has incorrect type", path); - goto done; + break; } if (section_header->size > fw_size) { WARNX(2, "%s is not a valid amd firmware: " "file is truncated", path); - goto done; + break; } if (section_header->size < sizeof(*fw_header)) { WARNX(2, "%s is not a valid amd firmware: " "section is too short", path); - goto done; + break; } fw_header = (const amd_10h_fw_header_t *)fw_data; fw_data += section_header->size; fw_size -= section_header->size; if (fw_header->processor_rev_id != equiv_id) { WARNX(1, "firmware processor_rev_id %x, equiv_id %x", fw_header->processor_rev_id, equiv_id); continue; /* different cpu */ } if (fw_header->patch_id <= revision) { WARNX(1, "patch_id %x, revision %x", fw_header->patch_id, revision); continue; /* not newer revision */ } if (fw_header->nb_dev_id != 0 || fw_header->sb_dev_id != 0) { WARNX(2, "Chipset-specific microcode is not supported"); } WARNX(3, "selecting revision: %x", fw_header->patch_id); revision = fw_header->patch_id; selected_fw = fw_header; selected_size = section_header->size; } if (fw_size != 0) { WARNX(2, "%s is not a valid amd firmware: " "file is truncated", path); - goto done; - } - - if (selected_fw != NULL) { - WARNX(1, "selected ucode size is %zu", selected_size); - fprintf(stderr, "%s: updating cpu %s to revision %#x... ", - path, dev, revision); - - args.data = __DECONST(void *, selected_fw); - args.size = selected_size; - error = ioctl(devfd, CPUCTL_UPDATE, &args); - if (error < 0) { - fprintf(stderr, "failed.\n"); - warn("ioctl()"); - goto done; - } - fprintf(stderr, "done.\n"); - } - - msrargs.msr = MSR_BIOS_SIGN; - error = ioctl(devfd, CPUCTL_RDMSR, &msrargs); - if (error < 0) { - WARN(0, "ioctl(%s)", dev); - goto done; + selected_fw = NULL; } - new_rev = (uint32_t)msrargs.data; - if (new_rev != revision) - WARNX(0, "revision after update %#x", new_rev); -done: - return; +found: + *selected_sizep = selected_size; + return (selected_fw); } diff --git a/usr.sbin/cpucontrol/Makefile b/usr.sbin/cpucontrol/Makefile index 41f573d02cc2..a468ca59b461 100644 --- a/usr.sbin/cpucontrol/Makefile +++ b/usr.sbin/cpucontrol/Makefile @@ -1,8 +1,12 @@ PROG= cpucontrol MAN= cpucontrol.8 -SRCS= cpucontrol.c intel.c amd.c amd10h.c via.c +SRCS= cpucontrol.c intel.c amd.c amd10h.c via.c ucode_subr.c + +.PATH: ${SRCTOP}/sys/x86/x86 NO_WCAST_ALIGN= +CFLAGS+= -I${.CURDIR} + .include diff --git a/usr.sbin/cpucontrol/amd.h b/usr.sbin/cpucontrol/amd.h index 7e53048a81d7..8e4efe60dca6 100644 --- a/usr.sbin/cpucontrol/amd.h +++ b/usr.sbin/cpucontrol/amd.h @@ -1,92 +1,51 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2006, 2008 Stanislav Sedov . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef AMD_H #define AMD_H /* * Prototypes. */ ucode_probe_t amd_probe; ucode_update_t amd_update; ucode_probe_t amd10h_probe; ucode_update_t amd10h_update; typedef struct amd_fw_header { uint32_t date; /* Update creation date. */ uint32_t xz0[2]; uint32_t checksum; /* ucode checksum. */ uint32_t xz1[2]; uint32_t signature; /* Low byte of cpuid(0). */ uint32_t magic; /* 0x0Xaaaaaa */ uint32_t xz2[8]; } amd_fw_header_t; #define AMD_MAGIC 0xaaaaaa -/* - * AMD family 10h and later. - */ -typedef struct amd_10h_fw_header { - uint32_t data_code; - uint32_t patch_id; - uint16_t mc_patch_data_id; - uint8_t mc_patch_data_len; - uint8_t init_flag; - uint32_t mc_patch_data_checksum; - uint32_t nb_dev_id; - uint32_t sb_dev_id; - uint16_t processor_rev_id; - uint8_t nb_rev_id; - uint8_t sb_rev_id; - uint8_t bios_api_rev; - uint8_t reserved1[3]; - uint32_t match_reg[8]; -} amd_10h_fw_header_t; - -typedef struct equiv_cpu_entry { - uint32_t installed_cpu; - uint32_t fixed_errata_mask; - uint32_t fixed_errata_compare; - uint16_t equiv_cpu; - uint16_t res; -} equiv_cpu_entry_t; - -typedef struct section_header { - uint32_t type; - uint32_t size; -} section_header_t; - -typedef struct container_header { - uint32_t magic; -} container_header_t; - -#define AMD_10H_MAGIC 0x414d44 -#define AMD_10H_EQUIV_TABLE_TYPE 0 -#define AMD_10H_uCODE_TYPE 1 - #endif /* !AMD_H */ diff --git a/usr.sbin/cpucontrol/amd10h.c b/usr.sbin/cpucontrol/amd10h.c index aceb6bfa2ba5..4fda44f0b797 100644 --- a/usr.sbin/cpucontrol/amd10h.c +++ b/usr.sbin/cpucontrol/amd10h.c @@ -1,288 +1,157 @@ /*- * Copyright (c) 2012 Andriy Gapon . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include +#include + #include #include #include #include #include #include #include #include "cpucontrol.h" #include "amd.h" int amd10h_probe(int fd) { char vendor[13]; cpuctl_cpuid_args_t idargs; uint32_t family; uint32_t signature; int error; idargs.level = 0; error = ioctl(fd, CPUCTL_CPUID, &idargs); if (error < 0) { WARN(0, "ioctl()"); return (1); } ((uint32_t *)vendor)[0] = idargs.data[1]; ((uint32_t *)vendor)[1] = idargs.data[3]; ((uint32_t *)vendor)[2] = idargs.data[2]; vendor[12] = '\0'; if (strncmp(vendor, AMD_VENDOR_ID, sizeof(AMD_VENDOR_ID)) != 0) return (1); idargs.level = 1; error = ioctl(fd, CPUCTL_CPUID, &idargs); if (error < 0) { WARN(0, "ioctl()"); return (1); } signature = idargs.data[0]; family = ((signature >> 8) & 0x0f) + ((signature >> 20) & 0xff); if (family < 0x10) return (1); return (0); } -/* - * NB: the format of microcode update files is not documented by AMD. - * It has been reverse engineered from studying Coreboot, illumos and Linux - * source code. - */ void amd10h_update(const struct ucode_update_params *params) { cpuctl_cpuid_args_t idargs; cpuctl_msr_args_t msrargs; cpuctl_update_args_t args; - const amd_10h_fw_header_t *fw_header; - const amd_10h_fw_header_t *selected_fw; - const equiv_cpu_entry_t *equiv_cpu_table; - const section_header_t *section_header; - const container_header_t *container_header; - const uint8_t *fw_data; const uint8_t *fw_image; const char *dev, *path; + const void *selected_fw; size_t fw_size; size_t selected_size; uint32_t revision; uint32_t new_rev; uint32_t signature; - uint16_t equiv_id; int devfd; - unsigned int i; int error; dev = params->dev_path; path = params->fw_path; devfd = params->devfd; fw_image = params->fwimage; fw_size = params->fwsize; assert(path); assert(dev); idargs.level = 1; error = ioctl(devfd, CPUCTL_CPUID, &idargs); if (error < 0) { WARN(0, "ioctl()"); goto done; } signature = idargs.data[0]; msrargs.msr = MSR_BIOS_SIGN; error = ioctl(devfd, CPUCTL_RDMSR, &msrargs); if (error < 0) { WARN(0, "ioctl(%s)", dev); goto done; } revision = (uint32_t)msrargs.data; - WARNX(1, "found cpu family %#x model %#x " - "stepping %#x extfamily %#x extmodel %#x.", - ((signature >> 8) & 0x0f) + ((signature >> 20) & 0xff), - (signature >> 4) & 0x0f, - (signature >> 0) & 0x0f, (signature >> 20) & 0xff, - (signature >> 16) & 0x0f); - WARNX(1, "microcode revision %#x", revision); - - /* - * Open the firmware file. - */ - WARNX(1, "checking %s for update.", path); - if (fw_size < - (sizeof(*container_header) + sizeof(*section_header))) { - WARNX(2, "file too short: %s", path); - goto done; - } - - /* - * mmap the whole image. - */ - fw_data = fw_image; - container_header = (const container_header_t *)fw_data; - if (container_header->magic != AMD_10H_MAGIC) { - WARNX(2, "%s is not a valid amd firmware: bad magic", path); - goto done; - } - fw_data += sizeof(*container_header); - fw_size -= sizeof(*container_header); - - section_header = (const section_header_t *)fw_data; - if (section_header->type != AMD_10H_EQUIV_TABLE_TYPE) { - WARNX(2, "%s is not a valid amd firmware: " - "first section is not CPU equivalence table", path); - goto done; - } - if (section_header->size == 0) { - WARNX(2, "%s is not a valid amd firmware: " - "first section is empty", path); - goto done; - } - fw_data += sizeof(*section_header); - fw_size -= sizeof(*section_header); - - if (section_header->size > fw_size) { - WARNX(2, "%s is not a valid amd firmware: " - "file is truncated", path); - goto done; - } - if (section_header->size < sizeof(*equiv_cpu_table)) { - WARNX(2, "%s is not a valid amd firmware: " - "first section is too short", path); - goto done; - } - equiv_cpu_table = (const equiv_cpu_entry_t *)fw_data; - fw_data += section_header->size; - fw_size -= section_header->size; - - equiv_id = 0; - for (i = 0; equiv_cpu_table[i].installed_cpu != 0; i++) { - if (signature == equiv_cpu_table[i].installed_cpu) { - equiv_id = equiv_cpu_table[i].equiv_cpu; - WARNX(3, "equiv_id: %x, signature %8x," - " equiv_cpu_table[%d] %8x", equiv_id, signature, - i, equiv_cpu_table[i].installed_cpu); - break; - } - } - if (equiv_id == 0) { - WARNX(2, "CPU is not found in the equivalence table"); - goto done; - } - - selected_fw = NULL; - selected_size = 0; - while (fw_size >= sizeof(*section_header)) { - section_header = (const section_header_t *)fw_data; - fw_data += sizeof(*section_header); - fw_size -= sizeof(*section_header); - if (section_header->type != AMD_10H_uCODE_TYPE) { - WARNX(2, "%s is not a valid amd firmware: " - "section has incorrect type", path); - goto done; - } - if (section_header->size > fw_size) { - WARNX(2, "%s is not a valid amd firmware: " - "file is truncated", path); - goto done; - } - if (section_header->size < sizeof(*fw_header)) { - WARNX(2, "%s is not a valid amd firmware: " - "section is too short", path); - goto done; - } - fw_header = (const amd_10h_fw_header_t *)fw_data; - fw_data += section_header->size; - fw_size -= section_header->size; - - if (fw_header->processor_rev_id != equiv_id) { - WARNX(1, "firmware processor_rev_id %x, equiv_id %x", - fw_header->processor_rev_id, equiv_id); - continue; /* different cpu */ - } - if (fw_header->patch_id <= revision) { - WARNX(1, "patch_id %x, revision %x", - fw_header->patch_id, revision); - continue; /* not newer revision */ - } - if (fw_header->nb_dev_id != 0 || fw_header->sb_dev_id != 0) { - WARNX(2, "Chipset-specific microcode is not supported"); - } - - WARNX(3, "selecting revision: %x", fw_header->patch_id); - revision = fw_header->patch_id; - selected_fw = fw_header; - selected_size = section_header->size; - } - - if (fw_size != 0) { - WARNX(2, "%s is not a valid amd firmware: " - "file is truncated", path); - goto done; - } + selected_fw = ucode_amd_find(path, signature, revision, fw_image, + fw_size, &selected_size); if (selected_fw != NULL) { WARNX(1, "selected ucode size is %zu", selected_size); fprintf(stderr, "%s: updating cpu %s to revision %#x... ", path, dev, revision); args.data = __DECONST(void *, selected_fw); args.size = selected_size; error = ioctl(devfd, CPUCTL_UPDATE, &args); if (error < 0) { fprintf(stderr, "failed.\n"); warn("ioctl()"); goto done; } fprintf(stderr, "done.\n"); } msrargs.msr = MSR_BIOS_SIGN; error = ioctl(devfd, CPUCTL_RDMSR, &msrargs); if (error < 0) { WARN(0, "ioctl(%s)", dev); goto done; } new_rev = (uint32_t)msrargs.data; if (new_rev != revision) WARNX(0, "revision after update %#x", new_rev); done: return; }