Skip to content

Commit

Permalink
x86/microcode/hygon: Add microcode loading support for Hygon processors
Browse files Browse the repository at this point in the history
Add support for loading Hygon microcode, which is compatible with AMD one.

Signed-off-by: Liao Xuan <[email protected]>
  • Loading branch information
Liao Xuan authored and Avenger-285714 committed May 25, 2024
1 parent b72df95 commit cf2cdfd
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 11 deletions.
13 changes: 12 additions & 1 deletion Documentation/arch/x86/microcode.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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::
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1312,7 +1312,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_LATE_LOADING
bool "Late microcode loading (DANGEROUS)"
Expand Down
52 changes: 44 additions & 8 deletions arch/x86/kernel/cpu/microcode/amd.c
Original file line number Diff line number Diff line change
Expand Up @@ -493,15 +493,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%.2xh.bin", family);
else if (x86_cpuid_vendor() == X86_VENDOR_HYGON)
snprintf(fw_name, sizeof(fw_name),
"hygon-ucode/microcode_hygon_fam%.2xh.bin", family);

if (firmware_request_builtin(&fw, fw_name)) {
cp->size = fw.size;
Expand All @@ -521,11 +524,18 @@ static void find_blobs_in_containers(unsigned int cpuid_1_eax, struct cpio_data

if (IS_ENABLED(CONFIG_X86_32)) {
uci = (struct ucode_cpu_info *)__pa_nodebug(ucode_cpu_info);
path = (const char *)__pa_nodebug(ucode_path);
if (x86_cpuid_vendor() == X86_VENDOR_HYGON)
path = (const char *)__pa_nodebug(
"kernel/x86/microcode/HygonGenuine.bin");
else
path = (const char *)__pa_nodebug(ucode_path);
use_pa = true;
} else {
uci = ucode_cpu_info;
path = ucode_path;
if (x86_cpuid_vendor() == X86_VENDOR_HYGON)
path = "kernel/x86/microcode/HygonGenuine.bin";
else
path = ucode_path;
use_pa = false;
}

Expand Down Expand Up @@ -561,8 +571,14 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax)
struct cont_desc desc = { 0 };
enum ucode_state ret;
struct cpio_data cp;
const char *path;

cp = find_microcode_in_initrd(ucode_path, false);
if (x86_cpuid_vendor() == X86_VENDOR_HYGON)
path = "kernel/x86/microcode/HygonGenuine.bin";
else
path = ucode_path;

cp = find_microcode_in_initrd(path, false);
if (!(cp.data && cp.size))
return -EINVAL;

Expand Down Expand Up @@ -904,13 +920,17 @@ 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;

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);
Expand Down Expand Up @@ -960,6 +980,22 @@ struct microcode_ops * __init init_amd_microcode(void)
return &microcode_amd_ops;
}

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

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

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();
Expand Down
22 changes: 21 additions & 1 deletion arch/x86/kernel/cpu/microcode/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@

#define DRIVER_VERSION "2.2"

#ifdef CONFIG_CPU_SUP_HYGON
static const struct microcode_ops *microcode_ops;
#else
static struct microcode_ops *microcode_ops;
#endif
static bool dis_ucode_ldr = true;

bool initrd_gone;
Expand Down Expand Up @@ -125,7 +129,8 @@ static bool __init check_loader_disabled_bsp(void)
if (native_cpuid_ecx(1) & BIT(31))
return *res;

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 *res;
}
Expand Down Expand Up @@ -158,6 +163,10 @@ void __init load_ucode_bsp(void)
intel = false;
break;

case X86_VENDOR_HYGON:
intel = false;
break;

default:
return;
}
Expand Down Expand Up @@ -198,6 +207,9 @@ void load_ucode_ap(void)
if (x86_family(cpuid_1_eax) >= 0x10)
load_ucode_amd_early(cpuid_1_eax);
break;
case X86_VENDOR_HYGON:
load_ucode_amd_early(cpuid_1_eax);
break;
default:
break;
}
Expand All @@ -222,6 +234,9 @@ static int __init save_microcode_in_initrd(void)
if (c->x86 >= 0x10)
ret = save_microcode_in_initrd_amd(cpuid_eax(1));
break;
case X86_VENDOR_HYGON:
ret = save_microcode_in_initrd_amd(cpuid_eax(1));
break;
default:
break;
}
Expand Down Expand Up @@ -316,6 +331,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;
}
Expand Down Expand Up @@ -642,6 +660,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");

Expand Down
12 changes: 12 additions & 0 deletions arch/x86/kernel/cpu/microcode/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa);
#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))))
Expand All @@ -81,6 +84,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;
}

Expand Down Expand Up @@ -114,6 +120,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
const struct microcode_ops *init_hygon_microcode(void);
#else /* CONFIG_CPU_SUP_HYGON */
static const 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);
Expand Down

0 comments on commit cf2cdfd

Please sign in to comment.