162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* -*- linux-c -*- ------------------------------------------------------- *
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *   Copyright (C) 1991, 1992 Linus Torvalds
562306a36Sopenharmony_ci *   Copyright 2007-2008 rPath, Inc. - All Rights Reserved
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * ----------------------------------------------------------------------- */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci/*
1062306a36Sopenharmony_ci * arch/x86/boot/cpu.c
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Check for obligatory CPU features and abort if the features are not
1362306a36Sopenharmony_ci * present.
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "boot.h"
1762306a36Sopenharmony_ci#include "cpustr.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic char *cpu_name(int level)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	static char buf[6];
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	if (level == 64) {
2462306a36Sopenharmony_ci		return "x86-64";
2562306a36Sopenharmony_ci	} else {
2662306a36Sopenharmony_ci		if (level == 15)
2762306a36Sopenharmony_ci			level = 6;
2862306a36Sopenharmony_ci		sprintf(buf, "i%d86", level);
2962306a36Sopenharmony_ci		return buf;
3062306a36Sopenharmony_ci	}
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic void show_cap_strs(u32 *err_flags)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	int i, j;
3662306a36Sopenharmony_ci	const unsigned char *msg_strs = (const unsigned char *)x86_cap_strs;
3762306a36Sopenharmony_ci	for (i = 0; i < NCAPINTS; i++) {
3862306a36Sopenharmony_ci		u32 e = err_flags[i];
3962306a36Sopenharmony_ci		for (j = 0; j < 32; j++) {
4062306a36Sopenharmony_ci			if (msg_strs[0] < i ||
4162306a36Sopenharmony_ci			    (msg_strs[0] == i && msg_strs[1] < j)) {
4262306a36Sopenharmony_ci				/* Skip to the next string */
4362306a36Sopenharmony_ci				msg_strs += 2;
4462306a36Sopenharmony_ci				while (*msg_strs++)
4562306a36Sopenharmony_ci					;
4662306a36Sopenharmony_ci			}
4762306a36Sopenharmony_ci			if (e & 1) {
4862306a36Sopenharmony_ci				if (msg_strs[0] == i &&
4962306a36Sopenharmony_ci				    msg_strs[1] == j &&
5062306a36Sopenharmony_ci				    msg_strs[2])
5162306a36Sopenharmony_ci					printf("%s ", msg_strs+2);
5262306a36Sopenharmony_ci				else
5362306a36Sopenharmony_ci					printf("%d:%d ", i, j);
5462306a36Sopenharmony_ci			}
5562306a36Sopenharmony_ci			e >>= 1;
5662306a36Sopenharmony_ci		}
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ciint validate_cpu(void)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	u32 *err_flags;
6362306a36Sopenharmony_ci	int cpu_level, req_level;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	check_cpu(&cpu_level, &req_level, &err_flags);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	if (cpu_level < req_level) {
6862306a36Sopenharmony_ci		printf("This kernel requires an %s CPU, ",
6962306a36Sopenharmony_ci		       cpu_name(req_level));
7062306a36Sopenharmony_ci		printf("but only detected an %s CPU.\n",
7162306a36Sopenharmony_ci		       cpu_name(cpu_level));
7262306a36Sopenharmony_ci		return -1;
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	if (err_flags) {
7662306a36Sopenharmony_ci		puts("This kernel requires the following features "
7762306a36Sopenharmony_ci		     "not present on the CPU:\n");
7862306a36Sopenharmony_ci		show_cap_strs(err_flags);
7962306a36Sopenharmony_ci		putchar('\n');
8062306a36Sopenharmony_ci		return -1;
8162306a36Sopenharmony_ci	} else if (check_knl_erratum()) {
8262306a36Sopenharmony_ci		return -1;
8362306a36Sopenharmony_ci	} else {
8462306a36Sopenharmony_ci		return 0;
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci}
87