Commit 8c3ee218 authored by Pu Wen's avatar Pu Wen
Browse files

x86/microcode/hygon: Add microcode loading support for Hygon processors

hygon inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I8U3G6


CVE: NA

---------------------------

Add support for loading Hygon microcode, which is compatible with AMD one.

Signed-off-by: default avatarPu Wen <puwen@hygon.cn>
parent 29efdd23
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ on Intel:
  kernel/x86/microcode/GenuineIntel.bin
on AMD  :
  kernel/x86/microcode/AuthenticAMD.bin
on Hygon:
  kernel/x86/microcode/HygonGenuine.bin

During BSP (BootStrapping Processor) boot (pre-SMP), the kernel
scans the microcode file in the initrd. If microcode matching the
@@ -69,6 +71,10 @@ here for future reference only).
  cd $TMPDIR
  mkdir -p $DSTDIR

  if [ -d /lib/firmware/hygon-ucode ]; then
          cat /lib/firmware/hygon-ucode/microcode_hygon*.bin > $DSTDIR/HygonGenuine.bin
  fi

  if [ -d /lib/firmware/amd-ucode ]; then
          cat /lib/firmware/amd-ucode/microcode_amd*.bin > $DSTDIR/AuthenticAMD.bin
  fi
@@ -217,7 +223,8 @@ currently supported.

Here's an example::

  CONFIG_EXTRA_FIRMWARE="intel-ucode/06-3a-09 amd-ucode/microcode_amd_fam15h.bin"
  CONFIG_EXTRA_FIRMWARE="intel-ucode/06-3a-09 \
    amd-ucode/microcode_amd_fam15h.bin hygon-ucode/microcode_hygon_fam18h.bin"
  CONFIG_EXTRA_FIRMWARE_DIR="/lib/firmware"

This basically means, you have the following tree structure locally::
@@ -227,6 +234,10 @@ This basically means, you have the following tree structure locally::
  ...
  |   |-- microcode_amd_fam15h.bin
  ...
  |-- hygon-ucode
  ...
  |   |-- microcode_hygon_fam18h.bin
  ...
  |-- intel-ucode
  ...
  |   |-- 06-3a-09
+1 −1
Original line number Diff line number Diff line
@@ -1317,7 +1317,7 @@ config X86_REBOOTFIXUPS

config MICROCODE
	def_bool y
	depends on CPU_SUP_AMD || CPU_SUP_INTEL
	depends on CPU_SUP_AMD || CPU_SUP_INTEL || CPU_SUP_HYGON

config MICROCODE_INITRD32
	def_bool y
+34 −6
Original line number Diff line number Diff line
@@ -477,15 +477,18 @@ static bool early_apply_microcode(u32 cpuid_1_eax, void *ucode, size_t size)

static bool get_builtin_microcode(struct cpio_data *cp, unsigned int family)
{
	char fw_name[36] = "amd-ucode/microcode_amd.bin";
	char fw_name[40] = "amd-ucode/microcode_amd.bin";
	struct firmware fw;

	if (IS_ENABLED(CONFIG_X86_32))
		return false;

	if (family >= 0x15)
	if (x86_cpuid_vendor() == X86_VENDOR_AMD && family >= 0x15)
		snprintf(fw_name, sizeof(fw_name),
			 "amd-ucode/microcode_amd_fam%02hhxh.bin", family);
	else if (x86_cpuid_vendor() == X86_VENDOR_HYGON)
		snprintf(fw_name, sizeof(fw_name),
			 "hygon-ucode/microcode_hygon_fam%02hhxh.bin", family);

	if (firmware_request_builtin(&fw, fw_name)) {
		cp->size = fw.size;
@@ -530,7 +533,9 @@ static int __init save_microcode_in_initrd(void)
	enum ucode_state ret;
	struct cpio_data cp;

	if (dis_ucode_ldr || c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10)
	if (dis_ucode_ldr ||
	    ((c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) &&
	     (c->x86_vendor != X86_VENDOR_HYGON)))
		return 0;

	find_blobs_in_containers(cpuid_1_eax, &cp);
@@ -883,7 +888,7 @@ static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t siz
 */
static enum ucode_state request_microcode_amd(int cpu, struct device *device)
{
	char fw_name[36] = "amd-ucode/microcode_amd.bin";
	char fw_name[40] = "amd-ucode/microcode_amd.bin";
	struct cpuinfo_x86 *c = &cpu_data(cpu);
	enum ucode_state ret = UCODE_NFOUND;
	const struct firmware *fw;
@@ -891,8 +896,12 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device)
	if (force_minrev)
		return UCODE_NFOUND;

	if (c->x86 >= 0x15)
		snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86);
	if (x86_cpuid_vendor() == X86_VENDOR_AMD && c->x86 >= 0x15)
		snprintf(fw_name, sizeof(fw_name),
			"amd-ucode/microcode_amd_fam%.2xh.bin", c->x86);
	else if (x86_cpuid_vendor() == X86_VENDOR_HYGON)
		snprintf(fw_name, sizeof(fw_name),
			"hygon-ucode/microcode_hygon_fam%.2xh.bin", c->x86);

	if (request_firmware_direct(&fw, (const char *)fw_name, device)) {
		pr_debug("failed to load file %s\n", fw_name);
@@ -943,6 +952,25 @@ struct microcode_ops * __init init_amd_microcode(void)
	return &microcode_amd_ops;
}

#ifdef CONFIG_CPU_SUP_HYGON
struct microcode_ops * __init init_hygon_microcode(void)
{
	struct cpuinfo_x86 *c = &boot_cpu_data;

	if (c->x86_vendor != X86_VENDOR_HYGON)
		return NULL;

	strscpy((char *)ucode_path, "kernel/x86/microcode/HygonGenuine.bin",
		sizeof(ucode_path));

	if (ucode_new_rev)
		pr_info_once("microcode updated early to new patch_level=0x%08x\n",
			     ucode_new_rev);

	return &microcode_amd_ops;
}
#endif

void __exit exit_amd_microcode(void)
{
	cleanup();
+14 −1
Original line number Diff line number Diff line
@@ -114,7 +114,8 @@ static bool __init check_loader_disabled_bsp(void)
	if (native_cpuid_ecx(1) & BIT(31))
		return true;

	if (x86_cpuid_vendor() == X86_VENDOR_AMD) {
	if (x86_cpuid_vendor() == X86_VENDOR_AMD ||
	    x86_cpuid_vendor() == X86_VENDOR_HYGON) {
		if (amd_check_current_patch_level())
			return true;
	}
@@ -147,6 +148,10 @@ void __init load_ucode_bsp(void)
		intel = false;
		break;

	case X86_VENDOR_HYGON:
		intel = false;
		break;

	default:
		return;
	}
@@ -178,6 +183,9 @@ void load_ucode_ap(void)
		if (x86_family(cpuid_1_eax) >= 0x10)
			load_ucode_amd_ap(cpuid_1_eax);
		break;
	case X86_VENDOR_HYGON:
		load_ucode_amd_ap(cpuid_1_eax);
		break;
	default:
		break;
	}
@@ -237,6 +245,9 @@ static void reload_early_microcode(unsigned int cpu)
		if (family >= 0x10)
			reload_ucode_amd(cpu);
		break;
	case X86_VENDOR_HYGON:
		reload_ucode_amd(cpu);
		break;
	default:
		break;
	}
@@ -822,6 +833,8 @@ static int __init microcode_init(void)
		microcode_ops = init_intel_microcode();
	else if (c->x86_vendor == X86_VENDOR_AMD)
		microcode_ops = init_amd_microcode();
	else if (c->x86_vendor == X86_VENDOR_HYGON)
		microcode_ops = init_hygon_microcode();
	else
		pr_err("no support for this CPU vendor\n");

+12 −0
Original line number Diff line number Diff line
@@ -49,6 +49,9 @@ struct cpio_data find_microcode_in_initrd(const char *path);
#define CPUID_AMD1 QCHAR('A', 'u', 't', 'h')
#define CPUID_AMD2 QCHAR('e', 'n', 't', 'i')
#define CPUID_AMD3 QCHAR('c', 'A', 'M', 'D')
#define CPUID_HYGON1 QCHAR('H', 'y', 'g', 'o')
#define CPUID_HYGON2 QCHAR('n', 'G', 'e', 'n')
#define CPUID_HYGON3 QCHAR('u', 'i', 'n', 'e')

#define CPUID_IS(a, b, c, ebx, ecx, edx)	\
		(!(((ebx) ^ (a)) | ((edx) ^ (b)) | ((ecx) ^ (c))))
@@ -75,6 +78,9 @@ static inline int x86_cpuid_vendor(void)
	if (CPUID_IS(CPUID_AMD1, CPUID_AMD2, CPUID_AMD3, ebx, ecx, edx))
		return X86_VENDOR_AMD;

	if (CPUID_IS(CPUID_HYGON1, CPUID_HYGON2, CPUID_HYGON3, ebx, ecx, edx))
		return X86_VENDOR_HYGON;

	return X86_VENDOR_UNKNOWN;
}

@@ -107,6 +113,12 @@ static inline struct microcode_ops *init_amd_microcode(void) { return NULL; }
static inline void exit_amd_microcode(void) { }
#endif /* !CONFIG_CPU_SUP_AMD */

#ifdef CONFIG_CPU_SUP_HYGON
struct microcode_ops *init_hygon_microcode(void);
#else /* CONFIG_CPU_SUP_HYGON */
static inline struct microcode_ops *init_hygon_microcode(void) { return NULL; }
#endif /* !CONFIG_CPU_SUP_HYGON */

#ifdef CONFIG_CPU_SUP_INTEL
void load_ucode_intel_bsp(void);
void load_ucode_intel_ap(void);